@@ -6329,3 +6329,103 @@ fn test_announce_disable_channels() {
6329
6329
let msg_events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
6330
6330
assert_eq ! ( msg_events. len( ) , 0 ) ;
6331
6331
}
6332
+
6333
+ #[ test]
6334
+ fn test_bump_penalty_txn_on_revoked_commitment ( ) {
6335
+ // In case of penalty txn with too low feerates for getting into mempools, RBF-bump them to be sure
6336
+ // we're able to claim outputs on revoked commitment transaction before timelocks expiration
6337
+
6338
+ let nodes = create_network ( 2 , & [ None , None ] ) ;
6339
+
6340
+ let chan = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1000000 , 59000000 , LocalFeatures :: new ( ) , LocalFeatures :: new ( ) ) ;
6341
+ let payment_preimage = route_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] ) [ ..] , 3000000 ) . 0 ;
6342
+ let route = nodes[ 1 ] . router . get_route ( & nodes[ 0 ] . node . get_our_node_id ( ) , None , & Vec :: new ( ) , 3000000 , 30 ) . unwrap ( ) ;
6343
+ send_along_route ( & nodes[ 1 ] , route, & vec ! ( & nodes[ 0 ] ) [ ..] , 3000000 ) ;
6344
+
6345
+ let revoked_txn = nodes[ 0 ] . node . channel_state . lock ( ) . unwrap ( ) . by_id . get ( & chan. 2 ) . unwrap ( ) . last_local_commitment_txn . clone ( ) ;
6346
+ // Revoked commitment txn with 4 outputs : to_local, to_remote, 1 outgoing HTLC, 1 incoming HTLC
6347
+ assert_eq ! ( revoked_txn[ 0 ] . output. len( ) , 4 ) ;
6348
+ assert_eq ! ( revoked_txn[ 0 ] . input. len( ) , 1 ) ;
6349
+ assert_eq ! ( revoked_txn[ 0 ] . input[ 0 ] . previous_output. txid, chan. 3 . txid( ) ) ;
6350
+ let revoked_txid = revoked_txn[ 0 ] . txid ( ) ;
6351
+
6352
+ let mut penalty_sum = 0 ;
6353
+ for outp in revoked_txn[ 0 ] . output . iter ( ) {
6354
+ if outp. script_pubkey . is_v0_p2wsh ( ) {
6355
+ penalty_sum += outp. value ;
6356
+ }
6357
+ }
6358
+
6359
+ // Connect blocks to change height_timer range to see if we use right soonest_timelock
6360
+ let header_114 = connect_blocks ( & nodes[ 1 ] . block_notifier , 114 , 0 , false , Default :: default ( ) ) ;
6361
+
6362
+ // Actually revoke tx by claiming a HTLC
6363
+ claim_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] ) [ ..] , payment_preimage, 3_000_000 ) ;
6364
+ let header = BlockHeader { version : 0x20000000 , prev_blockhash : header_114, merkle_root : Default :: default ( ) , time : 42 , bits : 42 , nonce : 42 } ;
6365
+ nodes[ 1 ] . block_notifier . block_connected ( & Block { header, txdata : vec ! [ revoked_txn[ 0 ] . clone( ) ] } , 115 ) ;
6366
+
6367
+ // One or more justice tx should have been broadcast, check it
6368
+ let penalty_1;
6369
+ let feerate_1;
6370
+ {
6371
+ let mut node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
6372
+ assert_eq ! ( node_txn. len( ) , 4 ) ; // justice tx (broadcasted from ChannelMonitor) * 2 (block-reparsing) + local commitment tx + local HTLC-timeout (broadcasted from ChannelManager)
6373
+ assert_eq ! ( node_txn[ 0 ] , node_txn[ 3 ] ) ;
6374
+ assert_eq ! ( node_txn[ 0 ] . input. len( ) , 3 ) ; // Penalty txn claims to_local, offered_htlc and received_htlc outputs
6375
+ assert_eq ! ( node_txn[ 0 ] . output. len( ) , 1 ) ;
6376
+ check_spends ! ( node_txn[ 0 ] , revoked_txn[ 0 ] . clone( ) ) ;
6377
+ let fee_1 = penalty_sum - node_txn[ 0 ] . output [ 0 ] . value ;
6378
+ feerate_1 = fee_1 * 1000 / node_txn[ 0 ] . get_weight ( ) as u64 ;
6379
+ penalty_1 = node_txn[ 0 ] . txid ( ) ;
6380
+ node_txn. clear ( ) ;
6381
+ } ;
6382
+
6383
+ // After exhaustion of height timer, a new bumped justice tx should have been broadcast, check it
6384
+ let header = connect_blocks ( & nodes[ 1 ] . block_notifier , 3 , 115 , true , header. bitcoin_hash ( ) ) ;
6385
+ let mut penalty_2 = penalty_1;
6386
+ let mut feerate_2 = 0 ;
6387
+ {
6388
+ let mut node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
6389
+ assert_eq ! ( node_txn. len( ) , 1 ) ;
6390
+ if node_txn[ 0 ] . input [ 0 ] . previous_output . txid == revoked_txid {
6391
+ assert_eq ! ( node_txn[ 0 ] . input. len( ) , 3 ) ; // Penalty txn claims to_local, offered_htlc and received_htlc outputs
6392
+ assert_eq ! ( node_txn[ 0 ] . output. len( ) , 1 ) ;
6393
+ check_spends ! ( node_txn[ 0 ] , revoked_txn[ 0 ] . clone( ) ) ;
6394
+ penalty_2 = node_txn[ 0 ] . txid ( ) ;
6395
+ // Verify new bumped tx is different from last claiming transaction, we don't want spurrious rebroadcast
6396
+ assert_ne ! ( penalty_2, penalty_1) ;
6397
+ let fee_2 = penalty_sum - node_txn[ 0 ] . output [ 0 ] . value ;
6398
+ feerate_2 = fee_2 * 1000 / node_txn[ 0 ] . get_weight ( ) as u64 ;
6399
+ // Verify 25% bump heuristic
6400
+ assert ! ( feerate_2 * 100 >= feerate_1 * 125 ) ;
6401
+ node_txn. clear ( ) ;
6402
+ }
6403
+ }
6404
+ assert_ne ! ( feerate_2, 0 ) ;
6405
+
6406
+ // After exhaustion of height timer for a 2nd time, a new bumped justice tx should have been broadcast, check it
6407
+ connect_blocks ( & nodes[ 1 ] . block_notifier , 3 , 118 , true , header) ;
6408
+ let penalty_3;
6409
+ let mut feerate_3 = 0 ;
6410
+ {
6411
+ let mut node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) ;
6412
+ assert_eq ! ( node_txn. len( ) , 1 ) ;
6413
+ if node_txn[ 0 ] . input [ 0 ] . previous_output . txid == revoked_txid {
6414
+ assert_eq ! ( node_txn[ 0 ] . input. len( ) , 3 ) ; // Penalty txn claims to_local, offered_htlc and received_htlc outputs
6415
+ assert_eq ! ( node_txn[ 0 ] . output. len( ) , 1 ) ;
6416
+ check_spends ! ( node_txn[ 0 ] , revoked_txn[ 0 ] . clone( ) ) ;
6417
+ penalty_3 = node_txn[ 0 ] . txid ( ) ;
6418
+ // Verify new bumped tx is different from last claiming transaction, we don't want spurrious rebroadcast
6419
+ assert_ne ! ( penalty_3, penalty_2) ;
6420
+ let fee_3 = penalty_sum - node_txn[ 0 ] . output [ 0 ] . value ;
6421
+ feerate_3 = fee_3 * 1000 / node_txn[ 0 ] . get_weight ( ) as u64 ;
6422
+ // Verify 25% bump heuristic
6423
+ assert ! ( feerate_3 * 100 >= feerate_2 * 125 ) ;
6424
+ node_txn. clear ( ) ;
6425
+ }
6426
+ }
6427
+ assert_ne ! ( feerate_3, 0 ) ;
6428
+
6429
+ nodes[ 1 ] . node . get_and_clear_pending_events ( ) ;
6430
+ nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
6431
+ }
0 commit comments