@@ -1291,7 +1291,8 @@ impl<S> Display for SignOrCreationError<S> {
12911291}
12921292
12931293mod utils {
1294- use { CreationError , Currency , Invoice , InvoiceBuilder } ;
1294+ use { Currency , Invoice , InvoiceBuilder , SemanticError , SignedRawInvoice } ;
1295+ use bech32:: { FromBase32 , ToBase32 , u5} ;
12951296 use bitcoin_hashes:: Hash ;
12961297 use lightning:: chain;
12971298 use lightning:: chain:: chaininterface:: { BroadcasterInterface , FeeEstimator } ;
@@ -1301,15 +1302,14 @@ mod utils {
13011302 use lightning:: routing:: network_graph:: RoutingFees ;
13021303 use lightning:: routing:: router:: RouteHintHop ;
13031304 use lightning:: util:: logger:: Logger ;
1304- use secp256k1:: Secp256k1 ;
13051305 use std:: ops:: Deref ;
13061306
13071307 /// Utility to construct an invoice.
13081308 #[ allow( dead_code) ]
13091309 pub fn from_channelmanager < Signer : Sign , M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
13101310 channelmanager : & ChannelManager < Signer , M , T , K , F , L > , amt_msat : Option < u64 > , description : String ,
1311- network : Currency ,
1312- ) -> Result < Invoice , CreationError >
1311+ network : Currency , keys_manager : & dyn KeysInterface < Signer = Signer >
1312+ ) -> Result < Invoice , SemanticError >
13131313 where
13141314 M :: Target : chain:: Watch < Signer > ,
13151315 T :: Target : BroadcasterInterface ,
@@ -1347,7 +1347,6 @@ mod utils {
13471347 7200 , // default invoice expiry is 2 hours
13481348 0 ,
13491349 ) ;
1350- let secp_ctx = Secp256k1 :: new ( ) ;
13511350 let our_node_pubkey = channelmanager. get_our_node_id ( ) ;
13521351 let mut invoice = InvoiceBuilder :: new ( network)
13531352 . description ( description)
@@ -1364,9 +1363,32 @@ mod utils {
13641363 invoice = invoice. route ( hint) ;
13651364 }
13661365
1367- invoice. build_signed ( |msg_hash| {
1368- secp_ctx. sign_recoverable ( msg_hash, & channelmanager. get_our_node_secret ( ) )
1369- } )
1366+ let raw_invoice = invoice. build_raw ( ) . unwrap ( ) ;
1367+ let hrp_str = raw_invoice. hrp . to_string ( ) ;
1368+ let hrp_bytes = hrp_str. as_bytes ( ) ;
1369+ let data_without_signature = raw_invoice. data . to_base32 ( ) ;
1370+ let mut invoice_preimage = Vec :: < u8 > :: from ( hrp_bytes) ;
1371+
1372+ let mut data_part = Vec :: from ( data_without_signature) ;
1373+ let overhang = ( data_part. len ( ) * 5 ) % 8 ;
1374+ if overhang > 0 {
1375+ // add padding if data does not end at a byte boundary
1376+ data_part. push ( u5:: try_from_u8 ( 0 ) . unwrap ( ) ) ;
1377+
1378+ // if overhang is in (1..3) we need to add u5(0) padding two times
1379+ if overhang < 3 {
1380+ data_part. push ( u5:: try_from_u8 ( 0 ) . unwrap ( ) ) ;
1381+ }
1382+ }
1383+
1384+ invoice_preimage. extend_from_slice ( & Vec :: < u8 > :: from_base32 ( & data_part)
1385+ . expect ( "No padding error may occur due to appended zero above." ) ) ;
1386+ let signature = match keys_manager. sign_invoice ( invoice_preimage) {
1387+ Ok ( sig) => sig,
1388+ Err ( _) => return Err ( SemanticError :: InvalidSignature )
1389+ } ;
1390+ let signed_raw_invoice: Result < SignedRawInvoice , SemanticError > = raw_invoice. sign ( |_| Ok ( signature) ) ;
1391+ Invoice :: from_signed ( signed_raw_invoice. unwrap ( ) )
13701392 }
13711393
13721394}
@@ -1696,7 +1718,7 @@ mod test {
16961718 let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
16971719 let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
16981720 let _chan = create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
1699- let invoice = :: utils:: from_channelmanager ( & nodes[ 1 ] . node , Some ( 10_000 ) , "test" . to_string ( ) , Currency :: BitcoinTestnet ) . unwrap ( ) ;
1721+ let invoice = :: utils:: from_channelmanager ( & nodes[ 1 ] . node , Some ( 10_000 ) , "test" . to_string ( ) , Currency :: BitcoinTestnet , nodes [ 1 ] . keys_manager ) . unwrap ( ) ;
17001722 assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 100_000 ) ) ;
17011723 assert_eq ! ( invoice. min_final_cltv_expiry( ) , Some ( & 9 ) ) ;
17021724 assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
0 commit comments