@@ -41,6 +41,9 @@ use lightning_invoice::RawBolt11Invoice;
41
41
use types:: features:: Features ;
42
42
use crate :: blinded_path:: BlindedHop ;
43
43
44
+ #[ cfg( trampoline) ]
45
+ use crate :: routing:: router:: Route ;
46
+
44
47
pub fn blinded_payment_path (
45
48
payment_secret : PaymentSecret , intro_node_min_htlc : u64 , intro_node_max_htlc : u64 ,
46
49
node_ids : Vec < PublicKey > , channel_upds : & [ & msgs:: UnsignedChannelUpdate ] ,
@@ -1958,3 +1961,103 @@ fn test_trampoline_inbound_payment_decoding() {
1958
1961
panic ! ( ) ;
1959
1962
} ;
1960
1963
}
1964
+
1965
+ #[ test]
1966
+ #[ cfg( trampoline) ]
1967
+ fn test_successful_trampoline_single_hop_receive ( ) {
1968
+ // Simulate a payment of A (0) -> B (1) -> C(Trampoline (blinded intro)) (2)
1969
+
1970
+ const TOTAL_NODE_COUNT : usize = 3 ;
1971
+ let secp_ctx = Secp256k1 :: new ( ) ;
1972
+
1973
+ let chanmon_cfgs = create_chanmon_cfgs ( TOTAL_NODE_COUNT ) ;
1974
+ let node_cfgs = create_node_cfgs ( TOTAL_NODE_COUNT , & chanmon_cfgs) ;
1975
+ let node_chanmgrs = create_node_chanmgrs ( TOTAL_NODE_COUNT , & node_cfgs, & vec ! [ None ; TOTAL_NODE_COUNT ] ) ;
1976
+ let mut nodes = create_network ( TOTAL_NODE_COUNT , & node_cfgs, & node_chanmgrs) ;
1977
+
1978
+ let ( _, _, chan_id_alice_bob, _) = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 ) ;
1979
+ let ( _, _, chan_id_bob_carol, _) = create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 1_000_000 , 0 ) ;
1980
+
1981
+ for i in 0 ..TOTAL_NODE_COUNT { // connect all nodes' blocks
1982
+ connect_blocks ( & nodes[ i] , ( TOTAL_NODE_COUNT as u32 ) * CHAN_CONFIRM_DEPTH + 1 - nodes[ i] . best_block_info ( ) . 1 ) ;
1983
+ }
1984
+
1985
+ let bob_node_id = nodes[ 1 ] . node ( ) . get_our_node_id ( ) ;
1986
+ let carol_node_id = nodes[ 2 ] . node ( ) . get_our_node_id ( ) ;
1987
+
1988
+ let alice_bob_scid = nodes[ 0 ] . node ( ) . list_channels ( ) . iter ( ) . find ( |c| c. channel_id == chan_id_alice_bob) . unwrap ( ) . short_channel_id . unwrap ( ) ;
1989
+ let bob_carol_scid = nodes[ 1 ] . node ( ) . list_channels ( ) . iter ( ) . find ( |c| c. channel_id == chan_id_bob_carol) . unwrap ( ) . short_channel_id . unwrap ( ) ;
1990
+
1991
+ let amt_msat = 1000 ;
1992
+ let ( payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash ( & nodes[ 2 ] , Some ( amt_msat) , None ) ;
1993
+ let payee_tlvs = UnauthenticatedReceiveTlvs {
1994
+ payment_secret,
1995
+ payment_constraints : PaymentConstraints {
1996
+ max_cltv_expiry : u32:: max_value ( ) ,
1997
+ htlc_minimum_msat : amt_msat,
1998
+ } ,
1999
+ payment_context : PaymentContext :: Bolt12Refund ( Bolt12RefundContext { } ) ,
2000
+ } ;
2001
+
2002
+ let nonce = Nonce ( [ 42u8 ; 16 ] ) ;
2003
+ let expanded_key = nodes[ 2 ] . keys_manager . get_inbound_payment_key ( ) ;
2004
+ let payee_tlvs = payee_tlvs. authenticate ( nonce, & expanded_key) ;
2005
+ let carol_unblinded_tlvs = payee_tlvs. encode ( ) ;
2006
+
2007
+ let path = [ ( carol_node_id, WithoutLength ( & carol_unblinded_tlvs) ) ] ;
2008
+ let carol_alice_trampoline_session_priv = secret_from_hex ( "a0f4b8d7b6c2d0ffdfaf718f76e9decaef4d9fb38a8c4addb95c4007cc3eee03" ) ;
2009
+ let carol_blinding_point = PublicKey :: from_secret_key ( & secp_ctx, & carol_alice_trampoline_session_priv) ;
2010
+ let carol_blinded_hops = blinded_path:: utils:: construct_blinded_hops (
2011
+ & secp_ctx, path. into_iter ( ) , & carol_alice_trampoline_session_priv
2012
+ ) . unwrap ( ) ;
2013
+
2014
+ let route = Route {
2015
+ paths : vec ! [ Path {
2016
+ hops: vec![
2017
+ // Bob
2018
+ RouteHop {
2019
+ pubkey: bob_node_id,
2020
+ node_features: NodeFeatures :: empty( ) ,
2021
+ short_channel_id: alice_bob_scid,
2022
+ channel_features: ChannelFeatures :: empty( ) ,
2023
+ fee_msat: 1000 ,
2024
+ cltv_expiry_delta: 48 ,
2025
+ maybe_announced_channel: false ,
2026
+ } ,
2027
+
2028
+ // Carol
2029
+ RouteHop {
2030
+ pubkey: carol_node_id,
2031
+ node_features: NodeFeatures :: empty( ) ,
2032
+ short_channel_id: bob_carol_scid,
2033
+ channel_features: ChannelFeatures :: empty( ) ,
2034
+ fee_msat: 0 ,
2035
+ cltv_expiry_delta: 48 ,
2036
+ maybe_announced_channel: false ,
2037
+ }
2038
+ ] ,
2039
+ blinded_tail: Some ( BlindedTail {
2040
+ trampoline_hops: vec![
2041
+ // Carol
2042
+ TrampolineHop {
2043
+ pubkey: carol_node_id,
2044
+ node_features: Features :: empty( ) ,
2045
+ fee_msat: amt_msat,
2046
+ cltv_expiry_delta: 24 ,
2047
+ } ,
2048
+ ] ,
2049
+ hops: carol_blinded_hops,
2050
+ blinding_point: carol_blinding_point,
2051
+ excess_final_cltv_expiry_delta: 39 ,
2052
+ final_value_msat: amt_msat,
2053
+ } )
2054
+ } ] ,
2055
+ route_params : None ,
2056
+ } ;
2057
+
2058
+ nodes[ 0 ] . node . send_payment_with_route ( route, payment_hash, RecipientOnionFields :: spontaneous_empty ( ) , PaymentId ( payment_hash. 0 ) ) . unwrap ( ) ;
2059
+
2060
+ check_added_monitors ! ( & nodes[ 0 ] , 1 ) ;
2061
+ pass_along_route ( & nodes[ 0 ] , & [ & [ & nodes[ 1 ] , & nodes[ 2 ] ] ] , amt_msat, payment_hash, payment_secret) ;
2062
+ claim_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] , & nodes[ 2 ] ] , payment_preimage) ;
2063
+ }
0 commit comments