@@ -197,7 +197,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail
197
197
if disconnect {
198
198
nodes[ 0 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) , false ) ;
199
199
nodes[ 1 ] . node . peer_disconnected ( & nodes[ 0 ] . node . get_our_node_id ( ) , false ) ;
200
- reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( true , true ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
200
+ reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( true , true ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
201
201
}
202
202
203
203
match persister_fail {
@@ -256,7 +256,7 @@ fn do_test_simple_monitor_temporary_update_fail(disconnect: bool, persister_fail
256
256
if disconnect {
257
257
nodes[ 0 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) , false ) ;
258
258
nodes[ 1 ] . node . peer_disconnected ( & nodes[ 0 ] . node . get_our_node_id ( ) , false ) ;
259
- reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( false , false ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
259
+ reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( false , false ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
260
260
}
261
261
262
262
// ...and make sure we can force-close a frozen channel
@@ -1947,7 +1947,7 @@ fn do_during_funding_monitor_fail(confirm_a_first: bool, restore_b_before_conf:
1947
1947
// Make sure nodes[1] isn't stupid enough to re-send the FundingLocked on reconnect
1948
1948
nodes[ 0 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) , false ) ;
1949
1949
nodes[ 1 ] . node . peer_disconnected ( & nodes[ 0 ] . node . get_our_node_id ( ) , false ) ;
1950
- reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( false , confirm_a_first) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
1950
+ reconnect_nodes ( & nodes[ 0 ] , & nodes[ 1 ] , ( false , confirm_a_first) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
1951
1951
assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1952
1952
assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
1953
1953
@@ -2250,3 +2250,119 @@ fn channel_holding_cell_serialize() {
2250
2250
do_channel_holding_cell_serialize ( true , false ) ;
2251
2251
do_channel_holding_cell_serialize ( false , true ) ; // last arg doesn't matter
2252
2252
}
2253
+
2254
+ #[ derive( PartialEq ) ]
2255
+ enum HTLCStatusAtDupClaim {
2256
+ Received ,
2257
+ HoldingCell ,
2258
+ Cleared ,
2259
+ }
2260
+ fn do_test_reconnect_dup_htlc_claims ( htlc_status : HTLCStatusAtDupClaim , second_fails : bool ) {
2261
+ // When receiving an update_fulfill_htlc message, we immediately forward the claim backwards
2262
+ // along the payment path before waiting for a full commitment_signed dance. This is great, but
2263
+ // can cause duplicative claims if a node sends an update_fulfill_htlc message, disconnects,
2264
+ // reconnects, and then has to re-send its update_fulfill_htlc message again.
2265
+ // In previous code, we didn't handle the double-claim correctly, spuriously closing the
2266
+ // channel on which the inbound HTLC was received.
2267
+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
2268
+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
2269
+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
2270
+ let mut nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
2271
+
2272
+ create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
2273
+ let chan_2 = create_announced_chan_between_nodes ( & nodes, 1 , 2 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) . 2 ;
2274
+
2275
+ let ( payment_preimage, payment_hash, _) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] , & nodes[ 2 ] ] , 100_000 ) ;
2276
+
2277
+ let mut as_raa = None ;
2278
+ if htlc_status == HTLCStatusAtDupClaim :: HoldingCell {
2279
+ // In order to get the HTLC claim into the holding cell at nodes[1], we need nodes[1] to be
2280
+ // awaiting a remote revoke_and_ack from nodes[0].
2281
+ let ( _, second_payment_hash, second_payment_secret) = get_payment_preimage_hash ! ( nodes[ 1 ] ) ;
2282
+ let route = get_route ( & nodes[ 0 ] . node . get_our_node_id ( ) , & nodes[ 0 ] . net_graph_msg_handler . network_graph . read ( ) . unwrap ( ) ,
2283
+ & nodes[ 1 ] . node . get_our_node_id ( ) , Some ( InvoiceFeatures :: known ( ) ) , None , & Vec :: new ( ) , 100_000 , TEST_FINAL_CLTV , nodes[ 1 ] . logger ) . unwrap ( ) ;
2284
+ nodes[ 0 ] . node . send_payment ( & route, second_payment_hash, & Some ( second_payment_secret) ) . unwrap ( ) ;
2285
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
2286
+
2287
+ let send_event = SendEvent :: from_event ( nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) . remove ( 0 ) ) ;
2288
+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & send_event. msgs [ 0 ] ) ;
2289
+ nodes[ 1 ] . node . handle_commitment_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & send_event. commitment_msg ) ;
2290
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
2291
+
2292
+ let ( bs_raa, bs_cs) = get_revoke_commit_msgs ! ( nodes[ 1 ] , nodes[ 0 ] . node. get_our_node_id( ) ) ;
2293
+ nodes[ 0 ] . node . handle_revoke_and_ack ( & nodes[ 1 ] . node . get_our_node_id ( ) , & bs_raa) ;
2294
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
2295
+ nodes[ 0 ] . node . handle_commitment_signed ( & nodes[ 1 ] . node . get_our_node_id ( ) , & bs_cs) ;
2296
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
2297
+
2298
+ as_raa = Some ( get_event_msg ! ( nodes[ 0 ] , MessageSendEvent :: SendRevokeAndACK , nodes[ 1 ] . node. get_our_node_id( ) ) ) ;
2299
+ }
2300
+
2301
+ let fulfill_msg = msgs:: UpdateFulfillHTLC {
2302
+ channel_id : chan_2,
2303
+ htlc_id : 0 ,
2304
+ payment_preimage,
2305
+ } ;
2306
+ if second_fails {
2307
+ assert ! ( nodes[ 2 ] . node. fail_htlc_backwards( & payment_hash) ) ;
2308
+ expect_pending_htlcs_forwardable ! ( nodes[ 2 ] ) ;
2309
+ check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
2310
+ get_htlc_update_msgs ! ( nodes[ 2 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
2311
+ } else {
2312
+ assert ! ( nodes[ 2 ] . node. claim_funds( payment_preimage) ) ;
2313
+ check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
2314
+ let cs_updates = get_htlc_update_msgs ! ( nodes[ 2 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
2315
+ assert_eq ! ( cs_updates. update_fulfill_htlcs. len( ) , 1 ) ;
2316
+ // Check that the message we're about to deliver matches the one generated:
2317
+ assert_eq ! ( fulfill_msg, cs_updates. update_fulfill_htlcs[ 0 ] ) ;
2318
+ }
2319
+ nodes[ 1 ] . node . handle_update_fulfill_htlc ( & nodes[ 2 ] . node . get_our_node_id ( ) , & fulfill_msg) ;
2320
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
2321
+
2322
+ let mut bs_updates = None ;
2323
+ if htlc_status != HTLCStatusAtDupClaim :: HoldingCell {
2324
+ bs_updates = Some ( get_htlc_update_msgs ! ( nodes[ 1 ] , nodes[ 0 ] . node. get_our_node_id( ) ) ) ;
2325
+ assert_eq ! ( bs_updates. as_ref( ) . unwrap( ) . update_fulfill_htlcs. len( ) , 1 ) ;
2326
+ nodes[ 0 ] . node . handle_update_fulfill_htlc ( & nodes[ 1 ] . node . get_our_node_id ( ) , & bs_updates. as_ref ( ) . unwrap ( ) . update_fulfill_htlcs [ 0 ] ) ;
2327
+ expect_payment_sent ! ( nodes[ 0 ] , payment_preimage) ;
2328
+ if htlc_status == HTLCStatusAtDupClaim :: Cleared {
2329
+ commitment_signed_dance ! ( nodes[ 0 ] , nodes[ 1 ] , & bs_updates. as_ref( ) . unwrap( ) . commitment_signed, false ) ;
2330
+ }
2331
+ } else {
2332
+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
2333
+ }
2334
+
2335
+ nodes[ 1 ] . node . peer_disconnected ( & nodes[ 2 ] . node . get_our_node_id ( ) , false ) ;
2336
+ nodes[ 2 ] . node . peer_disconnected ( & nodes[ 1 ] . node . get_our_node_id ( ) , false ) ;
2337
+
2338
+ if second_fails {
2339
+ reconnect_nodes ( & nodes[ 1 ] , & nodes[ 2 ] , ( false , false ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 1 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
2340
+ expect_pending_htlcs_forwardable ! ( nodes[ 1 ] ) ;
2341
+ } else {
2342
+ reconnect_nodes ( & nodes[ 1 ] , & nodes[ 2 ] , ( false , false ) , ( 0 , 0 ) , ( 1 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( 0 , 0 ) , ( false , false ) ) ;
2343
+ }
2344
+
2345
+ if htlc_status == HTLCStatusAtDupClaim :: HoldingCell {
2346
+ nodes[ 1 ] . node . handle_revoke_and_ack ( & nodes[ 0 ] . node . get_our_node_id ( ) , & as_raa. unwrap ( ) ) ;
2347
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
2348
+ expect_pending_htlcs_forwardable_ignore ! ( nodes[ 1 ] ) ; // We finally receive the second payment, but don't claim it
2349
+
2350
+ bs_updates = Some ( get_htlc_update_msgs ! ( nodes[ 1 ] , nodes[ 0 ] . node. get_our_node_id( ) ) ) ;
2351
+ assert_eq ! ( bs_updates. as_ref( ) . unwrap( ) . update_fulfill_htlcs. len( ) , 1 ) ;
2352
+ nodes[ 0 ] . node . handle_update_fulfill_htlc ( & nodes[ 1 ] . node . get_our_node_id ( ) , & bs_updates. as_ref ( ) . unwrap ( ) . update_fulfill_htlcs [ 0 ] ) ;
2353
+ expect_payment_sent ! ( nodes[ 0 ] , payment_preimage) ;
2354
+ }
2355
+ if htlc_status != HTLCStatusAtDupClaim :: Cleared {
2356
+ commitment_signed_dance ! ( nodes[ 0 ] , nodes[ 1 ] , & bs_updates. as_ref( ) . unwrap( ) . commitment_signed, false ) ;
2357
+ }
2358
+ }
2359
+
2360
+ #[ test]
2361
+ fn test_reconnect_dup_htlc_claims ( ) {
2362
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: Received , false ) ;
2363
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: HoldingCell , false ) ;
2364
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: Cleared , false ) ;
2365
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: Received , true ) ;
2366
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: HoldingCell , true ) ;
2367
+ do_test_reconnect_dup_htlc_claims ( HTLCStatusAtDupClaim :: Cleared , true ) ;
2368
+ }
0 commit comments