@@ -460,8 +460,10 @@ pub struct ChannelMonitor {
460460 // Used to track outpoint in the process of being claimed by our transactions. We need to scan all transactions
461461 // for inputs spending this. If height timer (u32) is expired and claim tx hasn't reached enough confirmations
462462 // before, use TxMaterial to regenerate a new claim tx with a satoshis-per-1000-weight-units higher than last
463- // one (u64).
464- our_claim_txn_waiting_first_conf : HashMap < BitcoinOutPoint , ( u32 , TxMaterial , u64 ) > ,
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
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 ) > ,
465467
466468 // Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which
467469 // we have to take actions once they reach enough confs. Key is a block height timer, i.e we enforce
@@ -624,6 +626,15 @@ impl ChannelMonitor {
624626 tx_weight
625627 }
626628
629+ fn get_height_timer ( current_height : u32 , timelock_expiration : u32 ) -> u32 {
630+ if timelock_expiration <= current_height || timelock_expiration - current_height <= 3 {
631+ return current_height + 1
632+ } else if timelock_expiration - current_height <= 15 {
633+ return current_height + 3
634+ }
635+ current_height + 15
636+ }
637+
627638 #[ inline]
628639 fn place_secret ( idx : u64 ) -> u8 {
629640 for i in 0 ..48 {
@@ -1129,6 +1140,8 @@ impl ChannelMonitor {
11291140 }
11301141 }
11311142 writer. write_all ( & byte_utils:: be64_to_array ( claim_tx_data. 2 ) ) ?;
1143+ writer. write_all ( & byte_utils:: be32_to_array ( claim_tx_data. 3 ) ) ?;
1144+ writer. write_all ( & byte_utils:: be32_to_array ( claim_tx_data. 4 ) ) ?;
11321145 }
11331146
11341147 writer. write_all ( & byte_utils:: be64_to_array ( self . onchain_events_waiting_threshold_conf . len ( ) as u64 ) ) ?;
@@ -1283,7 +1296,7 @@ impl ChannelMonitor {
12831296 witness : Vec :: new ( ) ,
12841297 } ) ;
12851298 inputs_desc. push ( InputDescriptors :: RevokedOutput ) ;
1286- inputs_info. push ( ( None , outp. value ) ) ;
1299+ inputs_info. push ( ( None , outp. value , self . our_to_self_delay as u32 ) ) ;
12871300 total_value += outp. value ;
12881301 } else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
12891302 spendable_outputs. push ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
@@ -1347,7 +1360,7 @@ impl ChannelMonitor {
13471360 if htlc. cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
13481361 inputs. push ( input) ;
13491362 inputs_desc. push ( if htlc. offered { InputDescriptors :: RevokedOfferedHTLC } else { InputDescriptors :: RevokedReceivedHTLC } ) ;
1350- inputs_info. push ( ( Some ( idx) , tx. output [ transaction_output_index as usize ] . value ) ) ;
1363+ inputs_info. push ( ( Some ( idx) , tx. output [ transaction_output_index as usize ] . value , htlc . cltv_expiry ) ) ;
13511364 total_value += tx. output [ transaction_output_index as usize ] . value ;
13521365 } else {
13531366 let mut single_htlc_tx = Transaction {
@@ -1360,14 +1373,15 @@ impl ChannelMonitor {
13601373 } ) ,
13611374 } ;
13621375 let predicted_weight = single_htlc_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ if htlc. offered { InputDescriptors :: RevokedOfferedHTLC } else { InputDescriptors :: RevokedReceivedHTLC } ] ) ;
1376+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
13631377 let mut used_feerate;
13641378 if subtract_high_prio_fee ! ( self , fee_estimator, single_htlc_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
13651379 let sighash_parts = bip143:: SighashComponents :: new ( & single_htlc_tx) ;
13661380 let ( redeemscript, revocation_key) = sign_input ! ( sighash_parts, single_htlc_tx. input[ 0 ] , Some ( idx) , htlc. amount_msat / 1000 ) ;
13671381 assert ! ( predicted_weight >= single_htlc_tx. get_weight( ) ) ;
13681382 match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
13691383 hash_map:: Entry :: Occupied ( _) => { } ,
1370- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , TxMaterial :: Revoked { script : redeemscript, pubkey : Some ( revocation_pubkey) , key : revocation_key, is_htlc : true , amount : htlc. amount_msat / 1000 } , used_feerate) ) ; }
1384+ 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 ) ) ; }
13711385 }
13721386 txn_to_broadcast. push ( single_htlc_tx) ;
13731387 }
@@ -1444,9 +1458,10 @@ impl ChannelMonitor {
14441458
14451459 for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
14461460 let ( redeemscript, revocation_key) = sign_input ! ( sighash_parts, input, info. 0 , info. 1 ) ;
1461+ let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
14471462 match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
14481463 hash_map:: Entry :: Occupied ( _) => { } ,
1449- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , 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) ) ; }
1464+ 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 ) ) ; }
14501465 }
14511466 }
14521467 assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1610,7 +1625,7 @@ impl ChannelMonitor {
16101625 if htlc. cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
16111626 inputs. push ( input) ;
16121627 inputs_desc. push ( if htlc. offered { InputDescriptors :: OfferedHTLC } else { InputDescriptors :: ReceivedHTLC } ) ;
1613- inputs_info. push ( ( payment_preimage, tx. output [ transaction_output_index as usize ] . value ) ) ;
1628+ inputs_info. push ( ( payment_preimage, tx. output [ transaction_output_index as usize ] . value , htlc . cltv_expiry ) ) ;
16141629 total_value += tx. output [ transaction_output_index as usize ] . value ;
16151630 } else {
16161631 let mut single_htlc_tx = Transaction {
@@ -1623,6 +1638,7 @@ impl ChannelMonitor {
16231638 } ) ,
16241639 } ;
16251640 let predicted_weight = single_htlc_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ if htlc. offered { InputDescriptors :: OfferedHTLC } else { InputDescriptors :: ReceivedHTLC } ] ) ;
1641+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
16261642 let mut used_feerate;
16271643 if subtract_high_prio_fee ! ( self , fee_estimator, single_htlc_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
16281644 let sighash_parts = bip143:: SighashComponents :: new ( & single_htlc_tx) ;
@@ -1634,7 +1650,7 @@ impl ChannelMonitor {
16341650 } ) ;
16351651 match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
16361652 hash_map:: Entry :: Occupied ( _) => { } ,
1637- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , used_feerate) ) ; }
1653+ 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 ) ) ; }
16381654 }
16391655 txn_to_broadcast. push ( single_htlc_tx) ;
16401656 }
@@ -1662,6 +1678,7 @@ impl ChannelMonitor {
16621678 } ) ,
16631679 } ;
16641680 let predicted_weight = timeout_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ InputDescriptors :: ReceivedHTLC ] ) ;
1681+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
16651682 let mut used_feerate;
16661683 if subtract_high_prio_fee ! ( self , fee_estimator, timeout_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
16671684 let sighash_parts = bip143:: SighashComponents :: new ( & timeout_tx) ;
@@ -1670,7 +1687,7 @@ impl ChannelMonitor {
16701687 //TODO: track SpendableOutputDescriptor
16711688 match self . our_claim_txn_waiting_first_conf . entry ( timeout_tx. input [ 0 ] . previous_output . clone ( ) ) {
16721689 hash_map:: Entry :: Occupied ( _) => { } ,
1673- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : None , amount : htlc. amount_msat / 1000 } , used_feerate) ) ; }
1690+ 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 ) ) ; }
16741691 }
16751692 }
16761693 txn_to_broadcast. push ( timeout_tx) ;
@@ -1702,9 +1719,10 @@ impl ChannelMonitor {
17021719
17031720 for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
17041721 let ( redeemscript, htlc_key) = sign_input ! ( sighash_parts, input, info. 1 , ( info. 0 ) . 0 . to_vec( ) ) ;
1722+ let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
17051723 match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
17061724 hash_map:: Entry :: Occupied ( _) => { } ,
1707- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , TxMaterial :: RemoteHTLC { script : redeemscript, key : htlc_key, preimage : Some ( * ( info. 0 ) ) , amount : info. 1 } , used_feerate) ) ; }
1725+ 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 ) ) ; }
17081726 }
17091727 }
17101728 assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1808,15 +1826,16 @@ impl ChannelMonitor {
18081826 assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
18091827 let outpoint = BitcoinOutPoint { txid : spend_tx. txid ( ) , vout : 0 } ;
18101828 let output = spend_tx. output [ 0 ] . clone ( ) ;
1829+ let height_timer = Self :: get_height_timer ( height, self . their_to_self_delay . unwrap ( ) as u32 ) ; // We can safely unwrap given we are past channel opening
18111830 match self . our_claim_txn_waiting_first_conf . entry ( spend_tx. input [ 0 ] . previous_output . clone ( ) ) {
18121831 hash_map:: Entry :: Occupied ( _) => { } ,
1813- hash_map:: Entry :: Vacant ( entry) => { entry. insert ( ( height + 3 , TxMaterial :: Revoked { script : redeemscript, pubkey : None , key : revocation_key, is_htlc : false , amount : tx. output [ 0 ] . value } , used_feerate) ) ; }
1832+ 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 ) ) ; }
18141833 }
18151834 ( Some ( spend_tx) , Some ( SpendableOutputDescriptor :: StaticOutput { outpoint, output } ) )
18161835 } else { ( None , None ) }
18171836 }
18181837
1819- 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 ) ) > ) {
1838+ 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 ) ) > ) {
18201839 let mut res = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
18211840 let mut spendable_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
18221841 let mut watch_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
@@ -1869,7 +1888,8 @@ impl ChannelMonitor {
18691888 htlc_timeout_tx. input [ 0 ] . witness . push ( htlc_script. clone ( ) . into_bytes ( ) ) ;
18701889
18711890 add_dynamic_output ! ( htlc_timeout_tx, 0 ) ;
1872- pending_claims. push ( ( htlc_timeout_tx. input [ 0 ] . previous_output . clone ( ) , ( height + 3 , TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : None , amount : htlc. amount_msat / 1000 } , 0 ) ) ) ;
1891+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1892+ 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) ) ) ;
18731893 res. push ( htlc_timeout_tx) ;
18741894 } else {
18751895 if let Some ( payment_preimage) = self . payment_preimages . get ( & htlc. payment_hash ) {
@@ -1888,7 +1908,8 @@ impl ChannelMonitor {
18881908 htlc_success_tx. input [ 0 ] . witness . push ( htlc_script. clone ( ) . into_bytes ( ) ) ;
18891909
18901910 add_dynamic_output ! ( htlc_success_tx, 0 ) ;
1891- pending_claims. push ( ( htlc_success_tx. input [ 0 ] . previous_output . clone ( ) , ( height + 3 , TxMaterial :: LocalHTLC { script : htlc_script, sigs : ( * their_sig, * our_sig) , preimage : Some ( * payment_preimage) , amount : htlc. amount_msat / 1000 } , 0 ) ) ) ;
1911+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1912+ 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) ) ) ;
18921913 res. push ( htlc_success_tx) ;
18931914 }
18941915 }
@@ -2190,7 +2211,7 @@ impl ChannelMonitor {
21902211 //- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
21912212 //- our claim tx on a commitment tx output
21922213 }
2193- self . our_claim_txn_waiting_first_conf . retain ( |_, ref mut v| if v. 0 == height + 3 { false } else { true } ) ;
2214+ self . our_claim_txn_waiting_first_conf . retain ( |_, ref mut v| if v. 3 == height { false } else { true } ) ;
21942215 self . last_block_hash = block_hash. clone ( ) ;
21952216 }
21962217
@@ -2659,7 +2680,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
26592680 _ => return Err ( DecodeError :: InvalidValue ) ,
26602681 } ;
26612682 let last_fee = Readable :: read ( reader) ?;
2662- our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee) ) ;
2683+ let timelock_expiration = Readable :: read ( reader) ?;
2684+ let height = Readable :: read ( reader) ?;
2685+ our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee, timelock_expiration, height) ) ;
26632686 }
26642687
26652688 let waiting_threshold_conf_len: u64 = Readable :: read ( reader) ?;
0 commit comments