10
10
//! Data structures and encoding for `invoice_request` messages.
11
11
12
12
use bitcoin:: blockdata:: constants:: ChainHash ;
13
- use bitcoin:: secp256k1:: PublicKey ;
13
+ use bitcoin:: network:: constants:: Network ;
14
+ use bitcoin:: secp256k1:: { Message , PublicKey , self } ;
14
15
use bitcoin:: secp256k1:: schnorr:: Signature ;
15
16
use core:: convert:: TryFrom ;
16
17
use core:: str:: FromStr ;
17
18
use io;
18
19
use ln:: features:: OfferFeatures ;
19
20
use offers:: merkle:: { SignatureTlvStream , self } ;
20
- use offers:: offer:: { Amount , OfferContents , OfferTlvStream , self } ;
21
+ use offers:: offer:: { Offer , OfferContents , OfferTlvStream , self } ;
21
22
use offers:: parse:: { Bech32Encode , ParseError , SemanticError } ;
22
23
use offers:: payer:: { PayerContents , PayerTlvStream , self } ;
23
24
use util:: ser:: { Readable , WithoutLength , Writeable , Writer } ;
24
25
26
+ ///
27
+ const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
28
+
29
+ ///
30
+ pub struct InvoiceRequestBuilder < ' a > {
31
+ offer : & ' a Offer ,
32
+ invoice_request : InvoiceRequestContents ,
33
+ }
34
+
35
+ impl < ' a > InvoiceRequestBuilder < ' a > {
36
+ pub ( super ) fn new ( offer : & ' a Offer , payer_id : PublicKey ) -> Self {
37
+ Self {
38
+ offer,
39
+ invoice_request : InvoiceRequestContents {
40
+ payer : PayerContents ( None ) , offer : offer. contents . clone ( ) , chain : None ,
41
+ amount_msats : None , features : None , quantity : None , payer_id, payer_note : None ,
42
+ } ,
43
+ }
44
+ }
45
+
46
+ ///
47
+ pub fn payer_info ( mut self , payer_info : Vec < u8 > ) -> Self {
48
+ self . invoice_request . payer = PayerContents ( Some ( payer_info) ) ;
49
+ self
50
+ }
51
+
52
+ ///
53
+ pub fn chain ( mut self , network : Network ) -> Result < Self , SemanticError > {
54
+ let chain_hash = ChainHash :: using_genesis_block ( network) ;
55
+ if !self . offer . supports_chain ( chain_hash) {
56
+ return Err ( SemanticError :: UnsupportedChain )
57
+ }
58
+
59
+ self . invoice_request . chain = Some ( chain_hash) ;
60
+ Ok ( self )
61
+ }
62
+
63
+ ///
64
+ pub fn amount_msats ( mut self , amount_msats : u64 ) -> Result < Self , SemanticError > {
65
+ if !self . offer . is_sufficient_amount ( amount_msats) {
66
+ return Err ( SemanticError :: InsufficientAmount ) ;
67
+ }
68
+
69
+ self . invoice_request . amount_msats = Some ( amount_msats) ;
70
+ Ok ( self )
71
+ }
72
+
73
+ ///
74
+ pub fn features ( mut self , features : OfferFeatures ) -> Self {
75
+ self . invoice_request . features = Some ( features) ;
76
+ self
77
+ }
78
+
79
+ ///
80
+ pub fn quantity ( mut self , quantity : u64 ) -> Result < Self , SemanticError > {
81
+ if !self . offer . is_valid_quantity ( quantity) {
82
+ return Err ( SemanticError :: InvalidQuantity ) ;
83
+ }
84
+
85
+ self . invoice_request . quantity = Some ( quantity) ;
86
+ Ok ( self )
87
+ }
88
+
89
+ ///
90
+ pub fn payer_note ( mut self , payer_note : String ) -> Self {
91
+ self . invoice_request . payer_note = Some ( payer_note) ;
92
+ self
93
+ }
94
+
95
+ ///
96
+ pub fn build_signed < F > ( self , sign : F ) -> Result < InvoiceRequest , secp256k1:: Error >
97
+ where F : FnOnce ( & Message ) -> Signature
98
+ {
99
+ // Use the offer bytes instead of the offer TLV stream as the offer may have contained
100
+ // unknown TLV records, which are not stored in `OfferContents`.
101
+ let ( payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream) =
102
+ self . invoice_request . as_tlv_stream ( ) ;
103
+ let offer_bytes = WithoutLength ( & self . offer . bytes ) ;
104
+ let unsigned_tlv_stream = ( payer_tlv_stream, offer_bytes, invoice_request_tlv_stream) ;
105
+
106
+ let mut bytes = Vec :: new ( ) ;
107
+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
108
+
109
+ let pubkey = self . invoice_request . payer_id ;
110
+ let signature = Some ( merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes, pubkey) ?) ;
111
+
112
+ // Append the signature TLV record to the bytes.
113
+ let signature_tlv_stream = merkle:: reference:: SignatureTlvStream {
114
+ signature : signature. as_ref ( ) ,
115
+ } ;
116
+ signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
117
+
118
+ Ok ( InvoiceRequest {
119
+ bytes,
120
+ contents : self . invoice_request ,
121
+ signature,
122
+ } )
123
+ }
124
+ }
125
+
25
126
///
26
127
pub struct InvoiceRequest {
27
128
bytes : Vec < u8 > ,
@@ -182,8 +283,7 @@ impl TryFrom<ParsedInvoiceRequest> for InvoiceRequest {
182
283
) ?;
183
284
184
285
if let Some ( signature) = & signature {
185
- let tag = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
186
- merkle:: verify_signature ( signature, tag, & bytes, contents. payer_id ) ?;
286
+ merkle:: verify_signature ( signature, SIGNATURE_TAG , & bytes, contents. payer_id ) ?;
187
287
}
188
288
189
289
Ok ( InvoiceRequest { bytes, contents, signature } )
@@ -203,25 +303,22 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
203
303
let payer = PayerContents ( payer_info. map ( Into :: into) ) ;
204
304
let offer = OfferContents :: try_from ( offer_tlv_stream) ?;
205
305
206
- let chain = match chain {
207
- None => None ,
208
- Some ( chain) if chain == offer. chain ( ) => Some ( chain) ,
209
- Some ( _) => return Err ( SemanticError :: UnsupportedChain ) ,
210
- } ;
306
+ if !offer. supports_chain ( chain. unwrap_or_else ( || offer. implied_chain ( ) ) ) {
307
+ return Err ( SemanticError :: UnsupportedChain ) ;
308
+ }
211
309
212
310
// TODO: Determine whether quantity should be accounted for
213
311
let amount_msats = match ( offer. amount ( ) , amount. map ( Into :: into) ) {
214
312
// TODO: Handle currency case
215
- ( Some ( Amount :: Currency { .. } ) , _) => return Err ( SemanticError :: UnexpectedCurrency ) ,
216
313
( Some ( _) , None ) => return Err ( SemanticError :: MissingAmount ) ,
217
- ( Some ( Amount :: Bitcoin { amount_msats : offer_amount_msats } ) , Some ( amount_msats) ) => {
218
- if amount_msats < * offer_amount_msats {
314
+ ( Some ( _ ) , Some ( amount_msats) ) => {
315
+ if !offer . is_sufficient_amount ( amount_msats) {
219
316
return Err ( SemanticError :: InsufficientAmount ) ;
220
317
} else {
221
318
Some ( amount_msats)
222
319
}
223
320
} ,
224
- ( _ , amount_msats) => amount_msats,
321
+ ( None , amount_msats) => amount_msats,
225
322
} ;
226
323
227
324
if let Some ( features) = & features {
0 commit comments