99
1010//! Data structures and encoding for `invoice_request` messages.
1111
12+ use bitcoin:: blockdata:: constants:: genesis_block;
1213use bitcoin:: hash_types:: BlockHash ;
13- use bitcoin:: secp256k1:: PublicKey ;
14+ use bitcoin:: network:: constants:: Network ;
15+ use bitcoin:: secp256k1:: { Message , PublicKey , self } ;
1416use bitcoin:: secp256k1:: schnorr:: Signature ;
1517use core:: convert:: TryFrom ;
1618use core:: str:: FromStr ;
1719use io;
1820use ln:: features:: OfferFeatures ;
1921use offers:: merkle:: { SignatureTlvStream , self } ;
20- use offers:: offer:: { Amount , OfferContents , OfferTlvStream , self } ;
22+ use offers:: offer:: { Offer , OfferContents , OfferTlvStream , self } ;
2123use offers:: parse:: { Bech32Encode , ParseError , SemanticError } ;
2224use offers:: payer:: { PayerContents , PayerTlvStream , self } ;
2325use util:: ser:: { Readable , WithoutLength , Writeable , Writer } ;
2426
27+ ///
28+ const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
29+
30+ ///
31+ pub struct InvoiceRequestBuilder < ' a > {
32+ offer : & ' a Offer ,
33+ invoice_request : InvoiceRequestContents ,
34+ }
35+
36+ impl < ' a > InvoiceRequestBuilder < ' a > {
37+ pub ( super ) fn new ( offer : & ' a Offer , payer_id : PublicKey ) -> Self {
38+ Self {
39+ offer,
40+ invoice_request : InvoiceRequestContents {
41+ payer : PayerContents ( None ) , offer : offer. contents . clone ( ) , chain : None ,
42+ amount_msats : None , features : None , quantity : None , payer_id, payer_note : None ,
43+ signature : None ,
44+ } ,
45+ }
46+ }
47+
48+ ///
49+ pub fn payer_info ( mut self , payer_info : Vec < u8 > ) -> Self {
50+ self . invoice_request . payer = PayerContents ( Some ( payer_info) ) ;
51+ self
52+ }
53+
54+ ///
55+ pub fn chain ( mut self , network : Network ) -> Result < Self , SemanticError > {
56+ let block_hash = genesis_block ( network) . block_hash ( ) ;
57+ if !self . offer . supports_chain ( block_hash) {
58+ return Err ( SemanticError :: UnsupportedChain )
59+ }
60+
61+ self . invoice_request . chain = Some ( block_hash) ;
62+ Ok ( self )
63+ }
64+
65+ ///
66+ pub fn amount_msats ( mut self , amount_msats : u64 ) -> Result < Self , SemanticError > {
67+ if !self . offer . is_sufficient_amount ( amount_msats) {
68+ return Err ( SemanticError :: InsufficientAmount ) ;
69+ }
70+
71+ self . invoice_request . amount_msats = Some ( amount_msats) ;
72+ Ok ( self )
73+ }
74+
75+ ///
76+ pub fn features ( mut self , features : OfferFeatures ) -> Self {
77+ self . invoice_request . features = Some ( features) ;
78+ self
79+ }
80+
81+ ///
82+ pub fn quantity ( mut self , quantity : u64 ) -> Result < Self , SemanticError > {
83+ if !self . offer . is_valid_quantity ( quantity) {
84+ return Err ( SemanticError :: InvalidQuantity ) ;
85+ }
86+
87+ self . invoice_request . quantity = Some ( quantity) ;
88+ Ok ( self )
89+ }
90+
91+ ///
92+ pub fn payer_note ( mut self , payer_note : String ) -> Self {
93+ self . invoice_request . payer_note = Some ( payer_note) ;
94+ self
95+ }
96+
97+ ///
98+ pub fn build_signed < F > ( mut self , sign : F ) -> Result < InvoiceRequest , secp256k1:: Error >
99+ where F : FnOnce ( & Message ) -> Signature
100+ {
101+ // Use the offer bytes instead of the offer TLV stream as the offer may have contained
102+ // unknown TLV records, which are not stored in `OfferContents`.
103+ let ( payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream, _) =
104+ self . invoice_request . as_tlv_stream ( ) ;
105+ let offer_bytes = WithoutLength ( & self . offer . bytes ) ;
106+ let unsigned_tlv_stream = ( payer_tlv_stream, offer_bytes, invoice_request_tlv_stream) ;
107+
108+ let mut bytes = Vec :: new ( ) ;
109+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
110+
111+ let pubkey = self . invoice_request . payer_id ;
112+ let signature = merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes, pubkey) ?;
113+ self . invoice_request . signature = Some ( signature) ;
114+
115+ // Append the signature TLV record to the bytes.
116+ let signature_tlv_stream = merkle:: reference:: SignatureTlvStream {
117+ signature : self . invoice_request . signature . as_ref ( ) ,
118+ } ;
119+ signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
120+
121+ Ok ( InvoiceRequest {
122+ bytes,
123+ contents : self . invoice_request ,
124+ } )
125+ }
126+ }
127+
25128///
26129pub struct InvoiceRequest {
27130 bytes : Vec < u8 > ,
@@ -169,8 +272,7 @@ impl FromStr for InvoiceRequest {
169272 let contents = InvoiceRequestContents :: try_from ( tlv_stream) ?;
170273
171274 if let Some ( signature) = & contents. signature {
172- let tag = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
173- merkle:: verify_signature ( signature, tag, & bytes, contents. payer_id ) ?;
275+ merkle:: verify_signature ( signature, SIGNATURE_TAG , & bytes, contents. payer_id ) ?;
174276 }
175277
176278 Ok ( InvoiceRequest { bytes, contents } )
@@ -191,25 +293,22 @@ impl TryFrom<FullInvoiceRequestTlvStream> for InvoiceRequestContents {
191293 let payer = PayerContents ( payer_info. map ( Into :: into) ) ;
192294 let offer = OfferContents :: try_from ( offer_tlv_stream) ?;
193295
194- let chain = match chain {
195- None => None ,
196- Some ( chain) if chain == offer. chain ( ) => Some ( chain) ,
197- Some ( _) => return Err ( SemanticError :: UnsupportedChain ) ,
198- } ;
296+ if !offer. supports_chain ( chain. unwrap_or_else ( || offer. implied_chain ( ) ) ) {
297+ return Err ( SemanticError :: UnsupportedChain ) ;
298+ }
199299
200300 // TODO: Determine whether quantity should be accounted for
201301 let amount_msats = match ( offer. amount ( ) , amount. map ( Into :: into) ) {
202302 // TODO: Handle currency case
203- ( Some ( Amount :: Currency { .. } ) , _) => return Err ( SemanticError :: UnexpectedCurrency ) ,
204303 ( Some ( _) , None ) => return Err ( SemanticError :: MissingAmount ) ,
205- ( Some ( Amount :: Bitcoin { amount_msats : offer_amount_msats } ) , Some ( amount_msats) ) => {
206- if amount_msats < * offer_amount_msats {
304+ ( Some ( _ ) , Some ( amount_msats) ) => {
305+ if !offer . is_sufficient_amount ( amount_msats) {
207306 return Err ( SemanticError :: InsufficientAmount ) ;
208307 } else {
209308 Some ( amount_msats)
210309 }
211310 } ,
212- ( _ , amount_msats) => amount_msats,
311+ ( None , amount_msats) => amount_msats,
213312 } ;
214313
215314 if let Some ( features) = & features {
0 commit comments