@@ -56,6 +56,16 @@ const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
56
56
/// it should be rather low as long as we still have to support 32bit time representations
57
57
const MAX_EXPIRY_TIME : u64 = 60 * 60 * 24 * 356 ;
58
58
59
+ /// Default expiry time as defined by [BOLT 11].
60
+ ///
61
+ /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
62
+ const DEFAULT_EXPIRY_TIME : u64 = 3600 ;
63
+
64
+ /// Default minimum final CLTV expiry as defined by [BOLT 11].
65
+ ///
66
+ /// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
67
+ const DEFAULT_MIN_FINAL_CLTV_EXPIRY : u64 = 18 ;
68
+
59
69
/// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
60
70
/// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
61
71
/// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
@@ -138,6 +148,7 @@ pub fn check_platform() {
138
148
/// .description("Coins pls!".into())
139
149
/// .payment_hash(payment_hash)
140
150
/// .current_timestamp()
151
+ /// .min_final_cltv_expiry(144)
141
152
/// .build_signed(|hash| {
142
153
/// Secp256k1::new().sign_recoverable(hash, &private_key)
143
154
/// })
@@ -156,7 +167,7 @@ pub fn check_platform() {
156
167
///
157
168
/// (C-not exported) as we likely need to manually select one set of boolean type parameters.
158
169
#[ derive( Eq , PartialEq , Debug , Clone ) ]
159
- pub struct InvoiceBuilder < D : tb:: Bool , H : tb:: Bool , T : tb:: Bool > {
170
+ pub struct InvoiceBuilder < D : tb:: Bool , H : tb:: Bool , T : tb:: Bool , C : tb :: Bool > {
160
171
currency : Currency ,
161
172
amount : Option < u64 > ,
162
173
si_prefix : Option < SiPrefix > ,
@@ -167,6 +178,7 @@ pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool> {
167
178
phantom_d : std:: marker:: PhantomData < D > ,
168
179
phantom_h : std:: marker:: PhantomData < H > ,
169
180
phantom_t : std:: marker:: PhantomData < T > ,
181
+ phantom_c : std:: marker:: PhantomData < C > ,
170
182
}
171
183
172
184
/// Represents a syntactically and semantically correct lightning BOLT11 invoice.
@@ -414,7 +426,7 @@ pub mod constants {
414
426
pub const TAG_FEATURES : u8 = 5 ;
415
427
}
416
428
417
- impl InvoiceBuilder < tb:: False , tb:: False , tb:: False > {
429
+ impl InvoiceBuilder < tb:: False , tb:: False , tb:: False , tb :: False > {
418
430
/// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
419
431
/// `InvoiceBuilder::build(self)` becomes available.
420
432
pub fn new ( currrency : Currency ) -> Self {
@@ -429,14 +441,15 @@ impl InvoiceBuilder<tb::False, tb::False, tb::False> {
429
441
phantom_d : std:: marker:: PhantomData ,
430
442
phantom_h : std:: marker:: PhantomData ,
431
443
phantom_t : std:: marker:: PhantomData ,
444
+ phantom_c : std:: marker:: PhantomData ,
432
445
}
433
446
}
434
447
}
435
448
436
- impl < D : tb:: Bool , H : tb:: Bool , T : tb:: Bool > InvoiceBuilder < D , H , T > {
449
+ impl < D : tb:: Bool , H : tb:: Bool , T : tb:: Bool , C : tb :: Bool > InvoiceBuilder < D , H , T , C > {
437
450
/// Helper function to set the completeness flags.
438
- fn set_flags < DN : tb:: Bool , HN : tb:: Bool , TN : tb:: Bool > ( self ) -> InvoiceBuilder < DN , HN , TN > {
439
- InvoiceBuilder :: < DN , HN , TN > {
451
+ fn set_flags < DN : tb:: Bool , HN : tb:: Bool , TN : tb:: Bool , CN : tb :: Bool > ( self ) -> InvoiceBuilder < DN , HN , TN , CN > {
452
+ InvoiceBuilder :: < DN , HN , TN , CN > {
440
453
currency : self . currency ,
441
454
amount : self . amount ,
442
455
si_prefix : self . si_prefix ,
@@ -447,6 +460,7 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
447
460
phantom_d : std:: marker:: PhantomData ,
448
461
phantom_h : std:: marker:: PhantomData ,
449
462
phantom_t : std:: marker:: PhantomData ,
463
+ phantom_c : std:: marker:: PhantomData ,
450
464
}
451
465
}
452
466
@@ -482,12 +496,6 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
482
496
self
483
497
}
484
498
485
- /// Sets `min_final_cltv_expiry`.
486
- pub fn min_final_cltv_expiry ( mut self , min_final_cltv_expiry : u64 ) -> Self {
487
- self . tagged_fields . push ( TaggedField :: MinFinalCltvExpiry ( MinFinalCltvExpiry ( min_final_cltv_expiry) ) ) ;
488
- self
489
- }
490
-
491
499
/// Adds a fallback address.
492
500
pub fn fallback ( mut self , fallback : Fallback ) -> Self {
493
501
self . tagged_fields . push ( TaggedField :: Fallback ( fallback) ) ;
@@ -511,7 +519,7 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
511
519
}
512
520
}
513
521
514
- impl < D : tb:: Bool , H : tb:: Bool > InvoiceBuilder < D , H , tb:: True > {
522
+ impl < D : tb:: Bool , H : tb:: Bool , C : tb :: Bool > InvoiceBuilder < D , H , tb:: True , C > {
515
523
/// Builds a `RawInvoice` if no `CreationError` occurred while construction any of the fields.
516
524
pub fn build_raw ( self ) -> Result < RawInvoice , CreationError > {
517
525
@@ -544,9 +552,9 @@ impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::True> {
544
552
}
545
553
}
546
554
547
- impl < H : tb:: Bool , T : tb:: Bool > InvoiceBuilder < tb:: False , H , T > {
555
+ impl < H : tb:: Bool , T : tb:: Bool , C : tb :: Bool > InvoiceBuilder < tb:: False , H , T , C > {
548
556
/// Set the description. This function is only available if no description (hash) was set.
549
- pub fn description ( mut self , description : String ) -> InvoiceBuilder < tb:: True , H , T > {
557
+ pub fn description ( mut self , description : String ) -> InvoiceBuilder < tb:: True , H , T , C > {
550
558
match Description :: new ( description) {
551
559
Ok ( d) => self . tagged_fields . push ( TaggedField :: Description ( d) ) ,
552
560
Err ( e) => self . error = Some ( e) ,
@@ -555,23 +563,23 @@ impl<H: tb::Bool, T: tb::Bool> InvoiceBuilder<tb::False, H, T> {
555
563
}
556
564
557
565
/// Set the description hash. This function is only available if no description (hash) was set.
558
- pub fn description_hash ( mut self , description_hash : sha256:: Hash ) -> InvoiceBuilder < tb:: True , H , T > {
566
+ pub fn description_hash ( mut self , description_hash : sha256:: Hash ) -> InvoiceBuilder < tb:: True , H , T , C > {
559
567
self . tagged_fields . push ( TaggedField :: DescriptionHash ( Sha256 ( description_hash) ) ) ;
560
568
self . set_flags ( )
561
569
}
562
570
}
563
571
564
- impl < D : tb:: Bool , T : tb:: Bool > InvoiceBuilder < D , tb:: False , T > {
572
+ impl < D : tb:: Bool , T : tb:: Bool , C : tb :: Bool > InvoiceBuilder < D , tb:: False , T , C > {
565
573
/// Set the payment hash. This function is only available if no payment hash was set.
566
- pub fn payment_hash ( mut self , hash : sha256:: Hash ) -> InvoiceBuilder < D , tb:: True , T > {
574
+ pub fn payment_hash ( mut self , hash : sha256:: Hash ) -> InvoiceBuilder < D , tb:: True , T , C > {
567
575
self . tagged_fields . push ( TaggedField :: PaymentHash ( Sha256 ( hash) ) ) ;
568
576
self . set_flags ( )
569
577
}
570
578
}
571
579
572
- impl < D : tb:: Bool , H : tb:: Bool > InvoiceBuilder < D , H , tb:: False > {
580
+ impl < D : tb:: Bool , H : tb:: Bool , C : tb :: Bool > InvoiceBuilder < D , H , tb:: False , C > {
573
581
/// Sets the timestamp.
574
- pub fn timestamp ( mut self , time : SystemTime ) -> InvoiceBuilder < D , H , tb:: True > {
582
+ pub fn timestamp ( mut self , time : SystemTime ) -> InvoiceBuilder < D , H , tb:: True , C > {
575
583
match PositiveTimestamp :: from_system_time ( time) {
576
584
Ok ( t) => self . timestamp = Some ( t) ,
577
585
Err ( e) => self . error = Some ( e) ,
@@ -581,14 +589,22 @@ impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::False> {
581
589
}
582
590
583
591
/// Sets the timestamp to the current UNIX timestamp.
584
- pub fn current_timestamp ( mut self ) -> InvoiceBuilder < D , H , tb:: True > {
592
+ pub fn current_timestamp ( mut self ) -> InvoiceBuilder < D , H , tb:: True , C > {
585
593
let now = PositiveTimestamp :: from_system_time ( SystemTime :: now ( ) ) ;
586
594
self . timestamp = Some ( now. expect ( "for the foreseeable future this shouldn't happen" ) ) ;
587
595
self . set_flags ( )
588
596
}
589
597
}
590
598
591
- impl InvoiceBuilder < tb:: True , tb:: True , tb:: True > {
599
+ impl < D : tb:: Bool , H : tb:: Bool , T : tb:: Bool > InvoiceBuilder < D , H , T , tb:: False > {
600
+ /// Sets `min_final_cltv_expiry`.
601
+ pub fn min_final_cltv_expiry ( mut self , min_final_cltv_expiry : u64 ) -> InvoiceBuilder < D , H , T , tb:: True > {
602
+ self . tagged_fields . push ( TaggedField :: MinFinalCltvExpiry ( MinFinalCltvExpiry ( min_final_cltv_expiry) ) ) ;
603
+ self . set_flags ( )
604
+ }
605
+ }
606
+
607
+ impl InvoiceBuilder < tb:: True , tb:: True , tb:: True , tb:: True > {
592
608
/// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
593
609
/// and MUST produce a recoverable signature valid for the given hash and if applicable also for
594
610
/// the included payee public key.
@@ -1044,16 +1060,19 @@ impl Invoice {
1044
1060
self . signed_invoice . recover_payee_pub_key ( ) . expect ( "was checked by constructor" ) . 0
1045
1061
}
1046
1062
1047
- /// Returns the invoice's expiry time if present
1063
+ /// Returns the invoice's expiry time, if present, otherwise [`DEFAULT_EXPIRY_TIME`].
1048
1064
pub fn expiry_time ( & self ) -> Duration {
1049
1065
self . signed_invoice . expiry_time ( )
1050
1066
. map ( |x| x. 0 )
1051
- . unwrap_or ( Duration :: from_secs ( 3600 ) )
1067
+ . unwrap_or ( Duration :: from_secs ( DEFAULT_EXPIRY_TIME ) )
1052
1068
}
1053
1069
1054
- /// Returns the invoice's `min_cltv_expiry` time if present
1055
- pub fn min_final_cltv_expiry ( & self ) -> Option < u64 > {
1056
- self . signed_invoice . min_final_cltv_expiry ( ) . map ( |x| x. 0 )
1070
+ /// Returns the invoice's `min_final_cltv_expiry` time, if present, otherwise
1071
+ /// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
1072
+ pub fn min_final_cltv_expiry ( & self ) -> u64 {
1073
+ self . signed_invoice . min_final_cltv_expiry ( )
1074
+ . map ( |x| x. 0 )
1075
+ . unwrap_or ( DEFAULT_MIN_FINAL_CLTV_EXPIRY )
1057
1076
}
1058
1077
1059
1078
/// Returns a list of all fallback addresses
@@ -1479,7 +1498,8 @@ mod test {
1479
1498
1480
1499
let builder = InvoiceBuilder :: new ( Currency :: Bitcoin )
1481
1500
. payment_hash ( sha256:: Hash :: from_slice ( & [ 0 ; 32 ] [ ..] ) . unwrap ( ) )
1482
- . current_timestamp ( ) ;
1501
+ . current_timestamp ( )
1502
+ . min_final_cltv_expiry ( 144 ) ;
1483
1503
1484
1504
let too_long_string = String :: from_iter (
1485
1505
( 0 ..1024 ) . map ( |_| '?' )
@@ -1596,7 +1616,6 @@ mod test {
1596
1616
. payee_pub_key ( public_key. clone ( ) )
1597
1617
. expiry_time ( Duration :: from_secs ( 54321 ) )
1598
1618
. min_final_cltv_expiry ( 144 )
1599
- . min_final_cltv_expiry ( 143 )
1600
1619
. fallback ( Fallback :: PubKeyHash ( [ 0 ; 20 ] ) )
1601
1620
. route ( route_1. clone ( ) )
1602
1621
. route ( route_2. clone ( ) )
@@ -1608,7 +1627,7 @@ mod test {
1608
1627
} ) . unwrap ( ) ;
1609
1628
1610
1629
assert ! ( invoice. check_signature( ) . is_ok( ) ) ;
1611
- assert_eq ! ( invoice. tagged_fields( ) . count( ) , 9 ) ;
1630
+ assert_eq ! ( invoice. tagged_fields( ) . count( ) , 8 ) ;
1612
1631
1613
1632
assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 123 ) ) ;
1614
1633
assert_eq ! ( invoice. currency( ) , Currency :: BitcoinTestnet ) ;
@@ -1618,7 +1637,7 @@ mod test {
1618
1637
) ;
1619
1638
assert_eq ! ( invoice. payee_pub_key( ) , Some ( & public_key) ) ;
1620
1639
assert_eq ! ( invoice. expiry_time( ) , Duration :: from_secs( 54321 ) ) ;
1621
- assert_eq ! ( invoice. min_final_cltv_expiry( ) , Some ( 144 ) ) ;
1640
+ assert_eq ! ( invoice. min_final_cltv_expiry( ) , 144 ) ;
1622
1641
assert_eq ! ( invoice. fallbacks( ) , vec![ & Fallback :: PubKeyHash ( [ 0 ; 20 ] ) ] ) ;
1623
1642
assert_eq ! ( invoice. routes( ) , vec![ & RouteHint ( route_1) , & RouteHint ( route_2) ] ) ;
1624
1643
assert_eq ! (
@@ -1630,4 +1649,28 @@ mod test {
1630
1649
let raw_invoice = builder. build_raw ( ) . unwrap ( ) ;
1631
1650
assert_eq ! ( raw_invoice, * invoice. into_signed_raw( ) . raw_invoice( ) )
1632
1651
}
1652
+
1653
+ #[ test]
1654
+ fn test_default_values ( ) {
1655
+ use :: * ;
1656
+ use secp256k1:: Secp256k1 ;
1657
+ use secp256k1:: key:: SecretKey ;
1658
+
1659
+ let signed_invoice = InvoiceBuilder :: new ( Currency :: Bitcoin )
1660
+ . description ( "Test" . into ( ) )
1661
+ . payment_hash ( sha256:: Hash :: from_slice ( & [ 0 ; 32 ] [ ..] ) . unwrap ( ) )
1662
+ . current_timestamp ( )
1663
+ . build_raw ( )
1664
+ . unwrap ( )
1665
+ . sign :: < _ , ( ) > ( |hash| {
1666
+ let privkey = SecretKey :: from_slice ( & [ 41 ; 32 ] ) . unwrap ( ) ;
1667
+ let secp_ctx = Secp256k1 :: new ( ) ;
1668
+ Ok ( secp_ctx. sign_recoverable ( hash, & privkey) )
1669
+ } )
1670
+ . unwrap ( ) ;
1671
+ let invoice = Invoice :: from_signed ( signed_invoice) . unwrap ( ) ;
1672
+
1673
+ assert_eq ! ( invoice. min_final_cltv_expiry( ) , DEFAULT_MIN_FINAL_CLTV_EXPIRY ) ;
1674
+ assert_eq ! ( invoice. expiry_time( ) , Duration :: from_secs( DEFAULT_EXPIRY_TIME ) ) ;
1675
+ }
1633
1676
}
0 commit comments