@@ -3422,6 +3422,13 @@ mod tests {
3422
3422
let payment_preimage_3 = route_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] ) [ ..] , 3000000 ) . 0 ;
3423
3423
// Get the will-be-revoked local txn from nodes[0]
3424
3424
let revoked_local_txn = nodes[ 0 ] . node . channel_state . lock ( ) . unwrap ( ) . by_id . iter ( ) . next ( ) . unwrap ( ) . 1 . last_local_commitment_txn . clone ( ) ;
3425
+ assert_eq ! ( revoked_local_txn. len( ) , 2 ) ; // First commitment tx, then HTLC tx
3426
+ assert_eq ! ( revoked_local_txn[ 0 ] . input. len( ) , 1 ) ;
3427
+ assert_eq ! ( revoked_local_txn[ 0 ] . input[ 0 ] . previous_output. txid, chan_5. 3 . txid( ) ) ;
3428
+ assert_eq ! ( revoked_local_txn[ 0 ] . output. len( ) , 2 ) ; // Only HTLC and output back to 0 are present
3429
+ assert_eq ! ( revoked_local_txn[ 1 ] . input. len( ) , 1 ) ;
3430
+ assert_eq ! ( revoked_local_txn[ 1 ] . input[ 0 ] . previous_output. txid, revoked_local_txn[ 0 ] . txid( ) ) ;
3431
+ assert_eq ! ( revoked_local_txn[ 1 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , 133 ) ; // HTLC-Timeout
3425
3432
// Revoke the old state
3426
3433
claim_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] ) [ ..] , payment_preimage_3) ;
3427
3434
@@ -3432,7 +3439,7 @@ mod tests {
3432
3439
let mut node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
3433
3440
assert_eq ! ( node_txn. len( ) , 3 ) ;
3434
3441
assert_eq ! ( node_txn. pop( ) . unwrap( ) , node_txn[ 0 ] ) ; // An outpoint registration will result in a 2nd block_connected
3435
- assert_eq ! ( node_txn[ 0 ] . input. len( ) , 1 ) ;
3442
+ assert_eq ! ( node_txn[ 0 ] . input. len( ) , 2 ) ; // We should claim the revoked output and the HTLC output
3436
3443
3437
3444
let mut funding_tx_map = HashMap :: new ( ) ;
3438
3445
funding_tx_map. insert ( revoked_local_txn[ 0 ] . txid ( ) , revoked_local_txn[ 0 ] . clone ( ) ) ;
@@ -3453,6 +3460,40 @@ mod tests {
3453
3460
}
3454
3461
3455
3462
#[ test]
3463
+ fn revoked_output_claim ( ) {
3464
+ // Simple test to ensure a node will claim a revoked output when a stale remote commitment
3465
+ // transaction is broadcast by its counterparty
3466
+ let nodes = create_network ( 2 ) ;
3467
+ let chan_1 = create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
3468
+ // node[0] is gonna to revoke an old state thus node[1] should be able to claim the revoked output
3469
+ let revoked_local_txn = nodes[ 0 ] . node . channel_state . lock ( ) . unwrap ( ) . by_id . get ( & chan_1. 2 ) . unwrap ( ) . last_local_commitment_txn . clone ( ) ;
3470
+ assert_eq ! ( revoked_local_txn. len( ) , 1 ) ;
3471
+ // Only output is the full channel value back to nodes[0]:
3472
+ assert_eq ! ( revoked_local_txn[ 0 ] . output. len( ) , 1 ) ;
3473
+ // Send a payment through, updating everyone's latest commitment txn
3474
+ send_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] ) [ ..] , 5000000 ) ;
3475
+
3476
+ // Inform nodes[1] that nodes[0] broadcast a stale tx
3477
+ let header = BlockHeader { version : 0x20000000 , prev_blockhash : Default :: default ( ) , merkle_root : Default :: default ( ) , time : 42 , bits : 42 , nonce : 42 } ;
3478
+ nodes[ 1 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ revoked_local_txn[ 0 ] . clone( ) ] } , 1 ) ;
3479
+ let node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
3480
+ assert_eq ! ( node_txn. len( ) , 3 ) ; // nodes[1] will broadcast justice tx twice, and its own local state once
3481
+
3482
+ assert_eq ! ( node_txn[ 0 ] , node_txn[ 2 ] ) ;
3483
+
3484
+ let mut revoked_tx_map = HashMap :: new ( ) ;
3485
+ revoked_tx_map. insert ( revoked_local_txn[ 0 ] . txid ( ) , revoked_local_txn[ 0 ] . clone ( ) ) ;
3486
+ node_txn[ 0 ] . verify ( & revoked_tx_map) . unwrap ( ) ;
3487
+
3488
+ revoked_tx_map. clear ( ) ;
3489
+ revoked_tx_map. insert ( chan_1. 3 . txid ( ) , chan_1. 3 . clone ( ) ) ;
3490
+ node_txn[ 1 ] . verify ( & revoked_tx_map) . unwrap ( ) ;
3491
+
3492
+ // Inform nodes[0] that a watchtower cheated on its behalf, so it will force-close the chan
3493
+ nodes[ 0 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ revoked_local_txn[ 0 ] . clone( ) ] } , 1 ) ;
3494
+ get_announce_close_broadcast_events ( & nodes, 0 , 1 ) ;
3495
+ }
3496
+
3456
3497
fn test_htlc_ignore_latest_remote_commitment ( ) {
3457
3498
// Test that HTLC transactions spending the latest remote commitment transaction are simply
3458
3499
// ignored if we cannot claim them. This originally tickled an invalid unwrap().
0 commit comments