@@ -40,6 +40,9 @@ use lightning_invoice::RawBolt11Invoice;
40
40
use types:: features:: Features ;
41
41
use crate :: blinded_path:: BlindedHop ;
42
42
43
+ #[ cfg( trampoline) ]
44
+ use crate :: routing:: gossip:: NodeId ;
45
+
43
46
pub fn blinded_payment_path (
44
47
payment_secret : PaymentSecret , intro_node_min_htlc : u64 , intro_node_max_htlc : u64 ,
45
48
node_ids : Vec < PublicKey > , channel_upds : & [ & msgs:: UnsignedChannelUpdate ] ,
@@ -1755,3 +1758,147 @@ fn test_combined_trampoline_onion_creation_vectors() {
1755
1758
assert_eq ! ( htlc_msat, 150_156_000 ) ;
1756
1759
assert_eq ! ( htlc_cltv, 800_060 ) ;
1757
1760
}
1761
+
1762
+ #[ test]
1763
+ #[ cfg( trampoline) ]
1764
+ fn test_trampoline_inbound_payment_decoding ( ) {
1765
+ let secp_ctx = Secp256k1 :: new ( ) ;
1766
+ let session_priv = secret_from_hex ( "0303030303030303030303030303030303030303030303030303030303030303" ) ;
1767
+
1768
+ let bob_secret = secret_from_hex ( "4242424242424242424242424242424242424242424242424242424242424242" ) ;
1769
+ let bob_node_id = PublicKey :: from_secret_key ( & secp_ctx, & bob_secret) ;
1770
+ let _bob_unblinded_tlvs = bytes_from_hex ( "011a0000000000000000000000000000000000000000000000000000020800000000000006c10a0800240000009627100c06000b69e505dc0e00fd023103123456" ) ;
1771
+ let carol_secret = secret_from_hex ( "4343434343434343434343434343434343434343434343434343434343434343" ) ;
1772
+ let carol_node_id = PublicKey :: from_secret_key ( & secp_ctx, & carol_secret) ;
1773
+ let _carol_unblinded_tlvs = bytes_from_hex ( "020800000000000004510821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0a0800300000006401f40c06000b69c105dc0e00" ) ;
1774
+ let dave_secret = secret_from_hex ( "4444444444444444444444444444444444444444444444444444444444444444" ) ;
1775
+ let dave_node_id = PublicKey :: from_secret_key ( & secp_ctx, & dave_secret) ;
1776
+ let _dave_unblinded_tlvs = bytes_from_hex ( "01230000000000000000000000000000000000000000000000000000000000000000000000020800000000000002310a060090000000fa0c06000b699105dc0e00" ) ;
1777
+ let eve_secret = secret_from_hex ( "4545454545454545454545454545454545454545454545454545454545454545" ) ;
1778
+ let _eve_node_id = PublicKey :: from_secret_key ( & secp_ctx, & eve_secret) ;
1779
+ let _eve_unblinded_tlvs = bytes_from_hex ( "011a00000000000000000000000000000000000000000000000000000604deadbeef0c06000b690105dc0e0f020000000000000000000000000000fdffff0206c1" ) ;
1780
+
1781
+ let path = Path {
1782
+ hops : vec ! [
1783
+ // Bob
1784
+ RouteHop {
1785
+ pubkey: bob_node_id,
1786
+ node_features: NodeFeatures :: empty( ) ,
1787
+ short_channel_id: 0 ,
1788
+ channel_features: ChannelFeatures :: empty( ) ,
1789
+ fee_msat: 0 ,
1790
+ cltv_expiry_delta: 0 ,
1791
+ maybe_announced_channel: false ,
1792
+ } ,
1793
+
1794
+ // Carol
1795
+ RouteHop {
1796
+ pubkey: carol_node_id,
1797
+ node_features: NodeFeatures :: empty( ) ,
1798
+ short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
1799
+ channel_features: ChannelFeatures :: empty( ) ,
1800
+ fee_msat: 150_153_000 ,
1801
+ cltv_expiry_delta: 0 ,
1802
+ maybe_announced_channel: false ,
1803
+ } ,
1804
+ ] ,
1805
+ blinded_tail : Some ( BlindedTail {
1806
+ trampoline_hops : vec ! [
1807
+ // Carol's pubkey
1808
+ TrampolineHop {
1809
+ pubkey: carol_node_id,
1810
+ node_features: Features :: empty( ) ,
1811
+ fee_msat: 2_500 ,
1812
+ cltv_expiry_delta: 24 ,
1813
+ } ,
1814
+ // Dave's pubkey (the intro node needs to be duplicated)
1815
+ TrampolineHop {
1816
+ pubkey: dave_node_id,
1817
+ node_features: Features :: empty( ) ,
1818
+ fee_msat: 150_500 , // incorporate both base and proportional fee
1819
+ cltv_expiry_delta: 36 ,
1820
+ }
1821
+ ] ,
1822
+ hops : vec ! [
1823
+ // Dave's blinded node id
1824
+ BlindedHop {
1825
+ blinded_node_id: pubkey_from_hex( "0295d40514096a8be54859e7dfe947b376eaafea8afe5cb4eb2c13ff857ed0b4be" ) ,
1826
+ encrypted_payload: bytes_from_hex( "0ccf3c8a58deaa603f657ee2a5ed9d604eb5c8ca1e5f801989afa8f3ea6d789bbdde2c7e7a1ef9ca8c38d2c54760febad8446d3f273ddb537569ef56613846ccd3aba78a" ) ,
1827
+ } ,
1828
+ // Eve's blinded node id
1829
+ BlindedHop {
1830
+ blinded_node_id: pubkey_from_hex( "020e2dbadcc2005e859819ddebbe88a834ae8a6d2b049233c07335f15cd1dc5f22" ) ,
1831
+ encrypted_payload: bytes_from_hex( "bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c" ) ,
1832
+ }
1833
+ ] ,
1834
+ blinding_point : pubkey_from_hex ( "02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) ,
1835
+ excess_final_cltv_expiry_delta : 0 ,
1836
+ final_value_msat : 150_000_000
1837
+ } )
1838
+ } ;
1839
+
1840
+ let payment_secret = PaymentSecret ( secret_from_hex ( "7494b65bc092b48a75465e43e29be807eb2cc535ce8aaba31012b8ff1ceac5da" ) . secret_bytes ( ) ) ;
1841
+
1842
+ let amt_msat = 150_000_001 ;
1843
+ let cur_height = 800_001 ;
1844
+ let recipient_onion_fields = RecipientOnionFields :: secret_only ( payment_secret) ;
1845
+ let ( bob_onion, _, _) = onion_utils:: create_payment_onion ( & secp_ctx, & path, & session_priv, amt_msat, & recipient_onion_fields, cur_height, & PaymentHash ( [ 0 ; 32 ] ) , & None , None , [ 0 ; 32 ] ) . unwrap ( ) ;
1846
+
1847
+ struct TestEcdhSigner {
1848
+ node_secret : SecretKey ,
1849
+ }
1850
+ impl NodeSigner for TestEcdhSigner {
1851
+ fn ecdh (
1852
+ & self , _recipient : Recipient , other_key : & PublicKey , tweak : Option < & Scalar > ,
1853
+ ) -> Result < SharedSecret , ( ) > {
1854
+ let mut node_secret = self . node_secret . clone ( ) ;
1855
+ if let Some ( tweak) = tweak {
1856
+ node_secret = self . node_secret . mul_tweak ( tweak) . map_err ( |_| ( ) ) ?;
1857
+ }
1858
+ Ok ( SharedSecret :: new ( other_key, & node_secret) )
1859
+ }
1860
+ fn get_inbound_payment_key ( & self ) -> ExpandedKey { unreachable ! ( ) }
1861
+ fn get_node_id ( & self , _recipient : Recipient ) -> Result < PublicKey , ( ) > { unreachable ! ( ) }
1862
+ fn sign_invoice (
1863
+ & self , _invoice : & RawBolt11Invoice , _recipient : Recipient ,
1864
+ ) -> Result < RecoverableSignature , ( ) > { unreachable ! ( ) }
1865
+ fn sign_bolt12_invoice (
1866
+ & self , _invoice : & UnsignedBolt12Invoice ,
1867
+ ) -> Result < schnorr:: Signature , ( ) > { unreachable ! ( ) }
1868
+ fn sign_gossip_message ( & self , _msg : UnsignedGossipMessage ) -> Result < Signature , ( ) > { unreachable ! ( ) }
1869
+ }
1870
+ let logger = test_utils:: TestLogger :: with_id ( "" . to_owned ( ) ) ;
1871
+
1872
+ let bob_update_add = update_add_msg ( 111_000 , 747_501 , None , bob_onion) ;
1873
+ let bob_node_signer = TestEcdhSigner { node_secret : bob_secret } ;
1874
+
1875
+ let ( bob_peeled_onion, next_packet_details_opt) = onion_payment:: decode_incoming_update_add_htlc_onion (
1876
+ & bob_update_add, & bob_node_signer, & logger, & secp_ctx
1877
+ ) . unwrap_or_else ( |_| panic ! ( ) ) ;
1878
+
1879
+ let ( carol_packet_bytes, carol_hmac) = if let onion_utils:: Hop :: Forward {
1880
+ next_hop_data : msgs:: InboundOnionForwardPayload { ..} , next_hop_hmac, new_packet_bytes, ..
1881
+ } = bob_peeled_onion {
1882
+ ( new_packet_bytes, next_hop_hmac)
1883
+ } else { panic ! ( ) } ;
1884
+
1885
+ let carol_packet_details = next_packet_details_opt. unwrap ( ) ;
1886
+ let carol_onion = msgs:: OnionPacket {
1887
+ version : 0 ,
1888
+ public_key : carol_packet_details. next_packet_pubkey ,
1889
+ hop_data : carol_packet_bytes,
1890
+ hmac : carol_hmac,
1891
+ } ;
1892
+ let carol_update_add = update_add_msg ( carol_packet_details. outgoing_amt_msat , carol_packet_details. outgoing_cltv_value , None , carol_onion) ;
1893
+
1894
+ let carol_node_signer = TestEcdhSigner { node_secret : carol_secret } ;
1895
+ let ( carol_peeled_onion, _) = onion_payment:: decode_incoming_update_add_htlc_onion (
1896
+ & carol_update_add, & carol_node_signer, & logger, & secp_ctx
1897
+ ) . unwrap_or_else ( |_| panic ! ( ) ) ;
1898
+
1899
+ let _carol_trampoline_update_add = if let onion_utils:: Hop :: TrampolineForward { next_trampoline_hop_data, .. } = carol_peeled_onion {
1900
+ assert_eq ! ( next_trampoline_hop_data. next_trampoline, NodeId :: from_pubkey( & dave_node_id) ) ;
1901
+ } else {
1902
+ panic ! ( ) ;
1903
+ } ;
1904
+ }
0 commit comments