@@ -461,9 +461,12 @@ pub struct ChannelMonitor {
461
461
// for inputs spending this. If height timer (u32) is expired and claim tx hasn't reached enough confirmations
462
462
// before, use TxMaterial to regenerate a new claim tx with a satoshis-per-1000-weight-units higher than last
463
463
// one (u64), if timelock expiration (u32) is near, decrease height timer, the in-between bumps delay.
464
- // Last field cached (u32) is height of outpoint confirmation, which is needed to flush this tracker
464
+ // We also cache height of outpoint confirmation (u32) , which is needed to flush this tracker
465
465
// in case of reorgs, given block timer are scaled on timer expiration we can't deduce from it original height.
466
- our_claim_txn_waiting_first_conf : HashMap < BitcoinOutPoint , ( u32 , TxMaterial , u64 , u32 , u32 ) > ,
466
+ // Last field cached (Option<Sha256dHash>) is txid of lastest claim tx, it shouldn't be useful for single-input claim
467
+ // tx but if we claimed outpoints at first in an aggregate one, they must stay claimed in an aggregate bumped
468
+ // one too to respect RBF rules.
469
+ our_claim_txn_waiting_first_conf : HashMap < BitcoinOutPoint , ( u32 , TxMaterial , u64 , u32 , u32 , Vec < BitcoinOutPoint > ) > ,
467
470
468
471
// Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which
469
472
// we have to take actions once they reach enough confs. Key is a block height timer, i.e we enforce
@@ -1142,6 +1145,10 @@ impl ChannelMonitor {
1142
1145
writer. write_all ( & byte_utils:: be64_to_array ( claim_tx_data. 2 ) ) ?;
1143
1146
writer. write_all ( & byte_utils:: be32_to_array ( claim_tx_data. 3 ) ) ?;
1144
1147
writer. write_all ( & byte_utils:: be32_to_array ( claim_tx_data. 4 ) ) ?;
1148
+ writer. write_all ( & byte_utils:: be64_to_array ( claim_tx_data. 5 . len ( ) as u64 ) ) ?;
1149
+ for inp in claim_tx_data. 5 . iter ( ) {
1150
+ inp. write ( writer) ?;
1151
+ }
1145
1152
}
1146
1153
1147
1154
writer. write_all ( & byte_utils:: be64_to_array ( self . onchain_events_waiting_threshold_conf . len ( ) as u64 ) ) ?;
@@ -1382,7 +1389,7 @@ impl ChannelMonitor {
1382
1389
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , single_htlc_tx. input[ 0 ] . previous_output. vout, single_htlc_tx. input[ 0 ] . previous_output. txid, height_timer) ;
1383
1390
match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
1384
1391
hash_map:: Entry :: Occupied ( _) => { } ,
1385
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : true , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height) ) ; }
1392
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : true , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height, Vec :: new ( ) ) ) ; }
1386
1393
}
1387
1394
txn_to_broadcast. push ( single_htlc_tx) ;
1388
1395
}
@@ -1457,13 +1464,17 @@ impl ChannelMonitor {
1457
1464
1458
1465
let sighash_parts = bip143:: SighashComponents :: new ( & spend_tx) ;
1459
1466
1467
+ let mut buddy_inputs = Vec :: new ( ) ;
1468
+ for inp in spend_tx. input . iter ( ) {
1469
+ buddy_inputs. push ( inp. previous_output . clone ( ) ) ;
1470
+ }
1460
1471
for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
1461
1472
let ( redeemscript, revocation_key) = sign_input ! ( sighash_parts, input, info. 0 , info. 1 ) ;
1462
1473
let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
1463
1474
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , input. previous_output. vout, input. previous_output. txid, height_timer) ;
1464
1475
match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
1465
1476
hash_map:: Entry :: Occupied ( _) => { } ,
1466
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : if info. 0 . is_some ( ) { Some ( revocation_pubkey) } else { None } , key : revocation_key, is_htlc : if info. 0 . is_some ( ) { true } else { false } , amount : info. 1 } , used_feerate, if !info. 0 . is_some ( ) { height + info. 2 } else { info. 2 } , height) ) ; }
1477
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : if info. 0 . is_some ( ) { Some ( revocation_pubkey) } else { None } , key : revocation_key, is_htlc : if info. 0 . is_some ( ) { true } else { false } , amount : info. 1 } , used_feerate, if !info. 0 . is_some ( ) { height + info. 2 } else { info. 2 } , height, buddy_inputs . clone ( ) ) ) ; }
1467
1478
}
1468
1479
}
1469
1480
assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1653,7 +1664,7 @@ impl ChannelMonitor {
1653
1664
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , single_htlc_tx. input[ 0 ] . previous_output. vout, single_htlc_tx. input[ 0 ] . previous_output. txid, height_timer) ;
1654
1665
match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
1655
1666
hash_map:: Entry :: Occupied ( _) => { } ,
1656
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height) ) ; }
1667
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height, Vec :: new ( ) ) ) ; }
1657
1668
}
1658
1669
txn_to_broadcast. push ( single_htlc_tx) ;
1659
1670
}
@@ -1691,7 +1702,7 @@ impl ChannelMonitor {
1691
1702
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , timeout_tx. input[ 0 ] . previous_output. vout, timeout_tx. input[ 0 ] . previous_output. txid, height_timer) ;
1692
1703
match self . our_claim_txn_waiting_first_conf . entry ( timeout_tx. input [ 0 ] . previous_output . clone ( ) ) {
1693
1704
hash_map:: Entry :: Occupied ( _) => { } ,
1694
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : None , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height) ) ; }
1705
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : None , amount : htlc. amount_msat / 1000 } , used_feerate, htlc. cltv_expiry , height, Vec :: new ( ) ) ) ; }
1695
1706
}
1696
1707
}
1697
1708
txn_to_broadcast. push ( timeout_tx) ;
@@ -1721,13 +1732,17 @@ impl ChannelMonitor {
1721
1732
1722
1733
let sighash_parts = bip143:: SighashComponents :: new ( & spend_tx) ;
1723
1734
1735
+ let mut buddy_inputs = Vec :: new ( ) ;
1736
+ for inp in spend_tx. input . iter ( ) {
1737
+ buddy_inputs. push ( inp. previous_output . clone ( ) ) ;
1738
+ }
1724
1739
for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
1725
1740
let ( redeemscript, htlc_key) = sign_input ! ( sighash_parts, input, info. 1 , ( info. 0 ) . 0 . to_vec( ) ) ;
1726
1741
let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
1727
1742
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , input. previous_output. vout, input. previous_output. txid, height_timer) ;
1728
1743
match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
1729
1744
hash_map:: Entry :: Occupied ( _) => { } ,
1730
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * ( info. 0 ) ) , amount : info. 1 } , used_feerate, info. 2 , height) ) ; }
1745
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * ( info. 0 ) ) , amount : info. 1 } , used_feerate, info. 2 , height, buddy_inputs . clone ( ) ) ) ; }
1731
1746
}
1732
1747
}
1733
1748
assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1835,13 +1850,13 @@ impl ChannelMonitor {
1835
1850
log_trace ! ( self , "Outpoint {}:{} is under claiming process, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}" , spend_tx. input[ 0 ] . previous_output. vout, spend_tx. input[ 0 ] . previous_output. txid, height_timer) ;
1836
1851
match self . our_claim_txn_waiting_first_conf . entry ( spend_tx. input [ 0 ] . previous_output . clone ( ) ) {
1837
1852
hash_map:: Entry :: Occupied ( _) => { } ,
1838
- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : None , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } , used_feerate, height + self . our_to_self_delay as u32 , height) ) ; }
1853
+ hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height_timer, TxMaterial :: Revoked { script : redeemscript, pubkey : None , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } , used_feerate, height + self . our_to_self_delay as u32 , height, Vec :: new ( ) ) ) ; }
1839
1854
}
1840
1855
( Some ( spend_tx) , Some ( SpendableOutputDescriptor :: StaticOutput { outpoint, output } ) )
1841
1856
} else { ( None , None ) }
1842
1857
}
1843
1858
1844
- fn broadcast_by_local_state ( & self , local_tx : & LocalSignedTx , per_commitment_point : & Option < PublicKey > , delayed_payment_base_key : & Option < SecretKey > , height : u32 ) -> ( Vec < Transaction > , Vec < SpendableOutputDescriptor > , Vec < TxOut > , Vec < ( BitcoinOutPoint , ( u32 , TxMaterial , u64 , u32 , u32 ) ) > ) {
1859
+ fn broadcast_by_local_state ( & self , local_tx : & LocalSignedTx , per_commitment_point : & Option < PublicKey > , delayed_payment_base_key : & Option < SecretKey > , height : u32 ) -> ( Vec < Transaction > , Vec < SpendableOutputDescriptor > , Vec < TxOut > , Vec < ( BitcoinOutPoint , ( u32 , TxMaterial , u64 , u32 , u32 , Vec < BitcoinOutPoint > ) ) > ) {
1845
1860
let mut res = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
1846
1861
let mut spendable_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
1847
1862
let mut watch_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
@@ -1895,7 +1910,7 @@ impl ChannelMonitor {
1895
1910
1896
1911
add_dynamic_output ! ( htlc_timeout_tx, 0 ) ;
1897
1912
let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1898
- pending_claims. push ( ( htlc_timeout_tx. input [ 0 ] . previous_output . clone ( ) , ( height_timer, TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : None , amount : htlc. amount_msat / 1000 } , 0 , htlc. cltv_expiry , height) ) ) ;
1913
+ pending_claims. push ( ( htlc_timeout_tx. input [ 0 ] . previous_output . clone ( ) , ( height_timer, TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : None , amount : htlc. amount_msat / 1000 } , 0 , htlc. cltv_expiry , height, Vec :: new ( ) ) ) ) ;
1899
1914
res. push ( htlc_timeout_tx) ;
1900
1915
} else {
1901
1916
if let Some ( payment_preimage) = self . payment_preimages . get ( & htlc. payment_hash ) {
@@ -1915,7 +1930,7 @@ impl ChannelMonitor {
1915
1930
1916
1931
add_dynamic_output ! ( htlc_success_tx, 0 ) ;
1917
1932
let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1918
- pending_claims. push ( ( htlc_success_tx. input [ 0 ] . previous_output . clone ( ) , ( height_timer, TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , 0 , htlc. cltv_expiry , height) ) ) ;
1933
+ pending_claims. push ( ( htlc_success_tx. input [ 0 ] . previous_output . clone ( ) , ( height_timer, TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , 0 , htlc. cltv_expiry , height, Vec :: new ( ) ) ) ) ;
1919
1934
res. push ( htlc_success_tx) ;
1920
1935
}
1921
1936
}
@@ -2210,9 +2225,10 @@ impl ChannelMonitor {
2210
2225
bump_candidates. push ( ( claimed_outpoint, claim_tx_data) ) ;
2211
2226
}
2212
2227
}
2213
- for candidate in bump_candidates {
2214
- if let Some ( ( new_timer, bumped_tx, feerate) ) = self . bump_claim_tx ( candidate. 0 , ( candidate. 1 ) . 0 , & ( candidate. 1 ) . 1 , ( candidate. 1 ) . 2 , fee_estimator) {
2215
- pending_claims. push ( ( * candidate. 0 , ( new_timer, ( candidate. 1 ) . 1 . clone ( ) , feerate, ( candidate. 1 ) . 3 , ( candidate. 1 ) . 4 ) ) ) ;
2228
+ // TODO: retrieve and sort aggregate claim outpoints based on last_txid
2229
+ for ( outpoint, ( height_timer, tx_material, old_feerate, timelock_expiration, seen_height, buddy_inputs) ) in bump_candidates. drain ( ..) {
2230
+ if let Some ( ( new_timer, bumped_tx, feerate) ) = self . bump_claim_tx ( outpoint, * height_timer, & tx_material, * old_feerate, fee_estimator) {
2231
+ pending_claims. push ( ( * outpoint, ( new_timer, * tx_material, feerate, * timelock_expiration, * seen_height, * buddy_inputs) ) ) ;
2216
2232
bumped_txn. append ( & mut vec ! [ bumped_tx] ) ;
2217
2233
}
2218
2234
}
@@ -2799,7 +2815,12 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
2799
2815
let last_fee = Readable :: read ( reader) ?;
2800
2816
let timelock_expiration = Readable :: read ( reader) ?;
2801
2817
let height = Readable :: read ( reader) ?;
2802
- our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee, timelock_expiration, height) ) ;
2818
+ let buddy_len: u64 = Readable :: read ( reader) ?;
2819
+ let mut buddy_inputs = Vec :: new ( ) ;
2820
+ for _ in 0 ..buddy_len {
2821
+ buddy_inputs. push ( Readable :: read ( reader) ?) ;
2822
+ }
2823
+ our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee, timelock_expiration, height, buddy_inputs) ) ;
2803
2824
}
2804
2825
2805
2826
let waiting_threshold_conf_len: u64 = Readable :: read ( reader) ?;
0 commit comments