@@ -2,6 +2,8 @@ use std::collections::HashMap;
22
33use bitcoin:: psbt:: Psbt ;
44use bitcoin:: { base64, Amount , FeeRate , OutPoint , Script , TxOut } ;
5+ use serde:: ser:: SerializeStruct ;
6+ use serde:: { Deserialize , Serialize , Serializer } ;
57
68use super :: { Error , InternalRequestError , RequestError , SelectionError } ;
79use crate :: psbt:: PsbtExt ;
@@ -105,14 +107,146 @@ fn subdirectory(pubkey: &bitcoin::secp256k1::PublicKey) -> String {
105107 base64:: encode_config ( pubkey, b64_config)
106108}
107109
108- #[ derive( Debug ) ]
110+ #[ derive( Debug , Clone , PartialEq ) ]
109111pub struct Enrolled {
110112 relay_url : url:: Url ,
111113 ohttp_config : Vec < u8 > ,
112114 ohttp_proxy : url:: Url ,
113115 s : bitcoin:: secp256k1:: KeyPair ,
114116}
115117
118+ impl Serialize for Enrolled {
119+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
120+ where
121+ S : Serializer ,
122+ {
123+ let mut state = serializer. serialize_struct ( "Enrolled" , 4 ) ?;
124+ state. serialize_field ( "relay_url" , & self . relay_url . to_string ( ) ) ?;
125+ state. serialize_field ( "ohttp_config" , & self . ohttp_config ) ?;
126+ state. serialize_field ( "ohttp_proxy" , & self . ohttp_proxy . to_string ( ) ) ?;
127+ state. serialize_field ( "s" , & self . s . secret_key ( ) . secret_bytes ( ) ) ?;
128+
129+ state. end ( )
130+ }
131+ }
132+
133+ use std:: fmt;
134+ use std:: str:: FromStr ;
135+
136+ use serde:: de:: { self , Deserializer , MapAccess , Visitor } ;
137+
138+ impl < ' de > Deserialize < ' de > for Enrolled {
139+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
140+ where
141+ D : Deserializer < ' de > ,
142+ {
143+ enum Field {
144+ RelayUrl ,
145+ OhttpConfig ,
146+ OhttpProxy ,
147+ S ,
148+ }
149+
150+ impl < ' de > Deserialize < ' de > for Field {
151+ fn deserialize < D > ( deserializer : D ) -> Result < Field , D :: Error >
152+ where
153+ D : Deserializer < ' de > ,
154+ {
155+ struct FieldVisitor ;
156+
157+ impl < ' de > Visitor < ' de > for FieldVisitor {
158+ type Value = Field ;
159+
160+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
161+ formatter. write_str ( "`relay_url`, `ohttp_config`, `ohttp_proxy`, or `s`" )
162+ }
163+
164+ fn visit_str < E > ( self , value : & str ) -> Result < Field , E >
165+ where
166+ E : de:: Error ,
167+ {
168+ match value {
169+ "relay_url" => Ok ( Field :: RelayUrl ) ,
170+ "ohttp_config" => Ok ( Field :: OhttpConfig ) ,
171+ "ohttp_proxy" => Ok ( Field :: OhttpProxy ) ,
172+ "s" => Ok ( Field :: S ) ,
173+ _ => Err ( de:: Error :: unknown_field ( value, FIELDS ) ) ,
174+ }
175+ }
176+ }
177+
178+ deserializer. deserialize_identifier ( FieldVisitor )
179+ }
180+ }
181+
182+ struct EnrolledVisitor ;
183+
184+ impl < ' de > Visitor < ' de > for EnrolledVisitor {
185+ type Value = Enrolled ;
186+
187+ fn expecting ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
188+ formatter. write_str ( "struct Enrolled" )
189+ }
190+
191+ fn visit_map < V > ( self , mut map : V ) -> Result < Enrolled , V :: Error >
192+ where
193+ V : MapAccess < ' de > ,
194+ {
195+ let mut relay_url = None ;
196+ let mut ohttp_config = None ;
197+ let mut ohttp_proxy = None ;
198+ let mut s = None ;
199+ while let Some ( key) = map. next_key ( ) ? {
200+ match key {
201+ Field :: RelayUrl => {
202+ if relay_url. is_some ( ) {
203+ return Err ( de:: Error :: duplicate_field ( "relay_url" ) ) ;
204+ }
205+ let url_str: String = map. next_value ( ) ?;
206+ relay_url = Some ( url:: Url :: parse ( & url_str) . map_err ( de:: Error :: custom) ?) ;
207+ }
208+ Field :: OhttpConfig => {
209+ if ohttp_config. is_some ( ) {
210+ return Err ( de:: Error :: duplicate_field ( "ohttp_config" ) ) ;
211+ }
212+ ohttp_config = Some ( map. next_value ( ) ?) ;
213+ }
214+ Field :: OhttpProxy => {
215+ if ohttp_proxy. is_some ( ) {
216+ return Err ( de:: Error :: duplicate_field ( "ohttp_proxy" ) ) ;
217+ }
218+ let proxy_str: String = map. next_value ( ) ?;
219+ ohttp_proxy =
220+ Some ( url:: Url :: parse ( & proxy_str) . map_err ( de:: Error :: custom) ?) ;
221+ }
222+ Field :: S => {
223+ if s. is_some ( ) {
224+ return Err ( de:: Error :: duplicate_field ( "s" ) ) ;
225+ }
226+ let s_bytes: Vec < u8 > = map. next_value ( ) ?;
227+ let secp = bitcoin:: secp256k1:: Secp256k1 :: new ( ) ;
228+ s = Some (
229+ bitcoin:: secp256k1:: KeyPair :: from_seckey_slice ( & secp, & s_bytes)
230+ . map_err ( de:: Error :: custom) ?,
231+ ) ;
232+ }
233+ }
234+ }
235+ let relay_url = relay_url. ok_or_else ( || de:: Error :: missing_field ( "relay_url" ) ) ?;
236+ let ohttp_config =
237+ ohttp_config. ok_or_else ( || de:: Error :: missing_field ( "ohttp_config" ) ) ?;
238+ let ohttp_proxy =
239+ ohttp_proxy. ok_or_else ( || de:: Error :: missing_field ( "ohttp_proxy" ) ) ?;
240+ let s = s. ok_or_else ( || de:: Error :: missing_field ( "s" ) ) ?;
241+ Ok ( Enrolled { relay_url, ohttp_config, ohttp_proxy, s } )
242+ }
243+ }
244+
245+ const FIELDS : & [ & str ] = & [ "relay_url" , "ohttp_config" , "ohttp_proxy" , "s" ] ;
246+ deserializer. deserialize_struct ( "Enrolled" , FIELDS , EnrolledVisitor )
247+ }
248+ }
249+
116250impl Enrolled {
117251 pub fn extract_req ( & self ) -> Result < ( Request , ohttp:: ClientResponse ) , Error > {
118252 let ( body, ohttp_ctx) = self . fallback_req_body ( ) ?;
@@ -172,6 +306,8 @@ impl Enrolled {
172306 crate :: v2:: ohttp_encapsulate ( & self . ohttp_config , "GET" , & self . fallback_target ( ) , None )
173307 }
174308
309+ pub fn pubkey ( & self ) -> [ u8 ; 33 ] { self . s . public_key ( ) . serialize ( ) }
310+
175311 pub fn fallback_target ( & self ) -> String {
176312 let pubkey = & self . s . public_key ( ) . serialize ( ) ;
177313 let b64_config = base64:: Config :: new ( base64:: CharacterSet :: UrlSafe , false ) ;
0 commit comments