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