@@ -455,8 +455,8 @@ pub struct ChannelMonitor {
455
455
// Used to track outpoint in the process of being claimed by our transactions. We need to scan all transactions
456
456
// for inputs spending this. If height timer (u32) is expired and claim tx hasn't reached enough confirmations
457
457
// before, use TxMaterial to regenerate a new claim tx with a satoshis-per-1000-weight-units higher than last
458
- // one (u64).
459
- our_claim_txn_waiting_first_conf : HashMap < BitcoinOutPoint , ( u32 , TxMaterial , u64 ) > ,
458
+ // one (u64), if timelock expiration (u32) is near, decrease height timer, the in-between bumps delay .
459
+ our_claim_txn_waiting_first_conf : HashMap < BitcoinOutPoint , ( u32 , TxMaterial , u64 , u32 ) > ,
460
460
461
461
// Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which
462
462
// we have to take actions once they reach enough confs. Key is a block height timer, i.e we enforce
@@ -619,6 +619,15 @@ impl ChannelMonitor {
619
619
tx_weight
620
620
}
621
621
622
+ fn get_height_timer ( current_height : u32 , timelock_expiration : u32 ) -> u32 {
623
+ if timelock_expiration <= current_height || timelock_expiration - current_height <= 3 {
624
+ return current_height + 1
625
+ } else if timelock_expiration - current_height <= 15 {
626
+ return current_height + 3
627
+ }
628
+ 15
629
+ }
630
+
622
631
#[ inline]
623
632
fn place_secret ( idx : u64 ) -> u8 {
624
633
for i in 0 ..48 {
@@ -1124,6 +1133,7 @@ impl ChannelMonitor {
1124
1133
}
1125
1134
}
1126
1135
writer. write_all ( & byte_utils:: be64_to_array ( claim_tx_data. 2 ) ) ?;
1136
+ writer. write_all ( & byte_utils:: be32_to_array ( claim_tx_data. 3 ) ) ?;
1127
1137
}
1128
1138
1129
1139
writer. write_all ( & byte_utils:: be64_to_array ( self . onchain_events_waiting_threshold_conf . len ( ) as u64 ) ) ?;
@@ -1278,7 +1288,7 @@ impl ChannelMonitor {
1278
1288
witness : Vec :: new ( ) ,
1279
1289
} ) ;
1280
1290
inputs_desc. push ( InputDescriptors :: RevokedOutput ) ;
1281
- inputs_info. push ( ( None , outp. value ) ) ;
1291
+ inputs_info. push ( ( None , outp. value , self . their_to_self_delay . unwrap ( ) as u32 ) ) ; // We can safely unwrap given we are past channel opening
1282
1292
total_value += outp. value ;
1283
1293
} else if Some ( & outp. script_pubkey ) == local_payment_p2wpkh. as_ref ( ) {
1284
1294
spendable_outputs. push ( SpendableOutputDescriptor :: DynamicOutputP2WPKH {
@@ -1342,7 +1352,7 @@ impl ChannelMonitor {
1342
1352
if htlc. cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
1343
1353
inputs. push ( input) ;
1344
1354
inputs_desc. push ( if htlc. offered { InputDescriptors :: RevokedOfferedHTLC } else { InputDescriptors :: RevokedReceivedHTLC } ) ;
1345
- inputs_info. push ( ( Some ( idx) , tx. output [ transaction_output_index as usize ] . value ) ) ;
1355
+ inputs_info. push ( ( Some ( idx) , tx. output [ transaction_output_index as usize ] . value , htlc . cltv_expiry ) ) ;
1346
1356
total_value += tx. output [ transaction_output_index as usize ] . value ;
1347
1357
} else {
1348
1358
let mut single_htlc_tx = Transaction {
@@ -1355,14 +1365,15 @@ impl ChannelMonitor {
1355
1365
} ) ,
1356
1366
} ;
1357
1367
let predicted_weight = single_htlc_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ if htlc. offered { InputDescriptors :: RevokedOfferedHTLC } else { InputDescriptors :: RevokedReceivedHTLC } ] ) ;
1368
+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1358
1369
let mut used_feerate;
1359
1370
if subtract_high_prio_fee ! ( self , fee_estimator, single_htlc_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
1360
1371
let sighash_parts = bip143:: SighashComponents :: new ( & single_htlc_tx) ;
1361
1372
let ( redeemscript, revocation_key) = sign_input ! ( sighash_parts, single_htlc_tx. input[ 0 ] , Some ( idx) , htlc. amount_msat / 1000 ) ;
1362
1373
assert ! ( predicted_weight >= single_htlc_tx. get_weight( ) ) ;
1363
1374
match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
1364
1375
hash_map:: Entry :: Occupied ( _) => { } ,
1365
- 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) ) ; }
1376
+ 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 ) ) ; }
1366
1377
}
1367
1378
txn_to_broadcast. push ( single_htlc_tx) ;
1368
1379
}
@@ -1439,9 +1450,10 @@ impl ChannelMonitor {
1439
1450
1440
1451
for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
1441
1452
let ( redeemscript, revocation_key) = sign_input ! ( sighash_parts, input, info. 0 , info. 1 ) ;
1453
+ let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
1442
1454
match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
1443
1455
hash_map:: Entry :: Occupied ( _) => { } ,
1444
- 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) ) ; }
1456
+ 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, info . 2 ) ) ; }
1445
1457
}
1446
1458
}
1447
1459
assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1605,7 +1617,7 @@ impl ChannelMonitor {
1605
1617
if htlc. cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
1606
1618
inputs. push ( input) ;
1607
1619
inputs_desc. push ( if htlc. offered { InputDescriptors :: OfferedHTLC } else { InputDescriptors :: ReceivedHTLC } ) ;
1608
- inputs_info. push ( ( payment_preimage, tx. output [ transaction_output_index as usize ] . value ) ) ;
1620
+ inputs_info. push ( ( payment_preimage, tx. output [ transaction_output_index as usize ] . value , htlc . cltv_expiry ) ) ;
1609
1621
total_value += tx. output [ transaction_output_index as usize ] . value ;
1610
1622
} else {
1611
1623
let mut single_htlc_tx = Transaction {
@@ -1618,6 +1630,7 @@ impl ChannelMonitor {
1618
1630
} ) ,
1619
1631
} ;
1620
1632
let predicted_weight = single_htlc_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ if htlc. offered { InputDescriptors :: OfferedHTLC } else { InputDescriptors :: ReceivedHTLC } ] ) ;
1633
+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1621
1634
let mut used_feerate;
1622
1635
if subtract_high_prio_fee ! ( self , fee_estimator, single_htlc_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
1623
1636
let sighash_parts = bip143:: SighashComponents :: new ( & single_htlc_tx) ;
@@ -1629,7 +1642,7 @@ impl ChannelMonitor {
1629
1642
} ) ;
1630
1643
match self . our_claim_txn_waiting_first_conf . entry ( single_htlc_tx. input [ 0 ] . previous_output . clone ( ) ) {
1631
1644
hash_map:: Entry :: Occupied ( _) => { } ,
1632
- 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) ) ; }
1645
+ 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 ) ) ; }
1633
1646
}
1634
1647
txn_to_broadcast. push ( single_htlc_tx) ;
1635
1648
}
@@ -1657,6 +1670,7 @@ impl ChannelMonitor {
1657
1670
} ) ,
1658
1671
} ;
1659
1672
let predicted_weight = timeout_tx. get_weight ( ) + Self :: get_witnesses_weight ( & [ InputDescriptors :: ReceivedHTLC ] ) ;
1673
+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1660
1674
let mut used_feerate;
1661
1675
if subtract_high_prio_fee ! ( self , fee_estimator, timeout_tx. output[ 0 ] . value, predicted_weight, tx. txid( ) , used_feerate) {
1662
1676
let sighash_parts = bip143:: SighashComponents :: new ( & timeout_tx) ;
@@ -1665,7 +1679,7 @@ impl ChannelMonitor {
1665
1679
//TODO: track SpendableOutputDescriptor
1666
1680
match self . our_claim_txn_waiting_first_conf . entry ( timeout_tx. input [ 0 ] . previous_output . clone ( ) ) {
1667
1681
hash_map:: Entry :: Occupied ( _) => { } ,
1668
- 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) ) ; }
1682
+ 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 ) ) ; }
1669
1683
}
1670
1684
}
1671
1685
txn_to_broadcast. push ( timeout_tx) ;
@@ -1697,9 +1711,10 @@ impl ChannelMonitor {
1697
1711
1698
1712
for ( input, info) in spend_tx. input . iter_mut ( ) . zip ( inputs_info. iter ( ) ) {
1699
1713
let ( redeemscript, htlc_key) = sign_input ! ( sighash_parts, input, info. 1 , ( info. 0 ) . 0 . to_vec( ) ) ;
1714
+ let height_timer = Self :: get_height_timer ( height, info. 2 ) ;
1700
1715
match self . our_claim_txn_waiting_first_conf . entry ( input. previous_output . clone ( ) ) {
1701
1716
hash_map:: Entry :: Occupied ( _) => { } ,
1702
- 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) ) ; }
1717
+ 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 ) ) ; }
1703
1718
}
1704
1719
}
1705
1720
assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
@@ -1803,15 +1818,16 @@ impl ChannelMonitor {
1803
1818
assert ! ( predicted_weight >= spend_tx. get_weight( ) ) ;
1804
1819
let outpoint = BitcoinOutPoint { txid : spend_tx. txid ( ) , vout : 0 } ;
1805
1820
let output = spend_tx. output [ 0 ] . clone ( ) ;
1821
+ 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
1806
1822
match self . our_claim_txn_waiting_first_conf . entry ( spend_tx. input [ 0 ] . previous_output . clone ( ) ) {
1807
1823
hash_map:: Entry :: Occupied ( _) => { } ,
1808
- 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) ) ; }
1824
+ 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, self . their_to_self_delay . unwrap ( ) as u32 ) ) ; }
1809
1825
}
1810
1826
( Some ( spend_tx) , Some ( SpendableOutputDescriptor :: StaticOutput { outpoint, output } ) )
1811
1827
} else { ( None , None ) }
1812
1828
}
1813
1829
1814
- 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 ) ) > ) {
1830
+ 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 ) ) > ) {
1815
1831
let mut res = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
1816
1832
let mut spendable_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
1817
1833
let mut watch_outputs = Vec :: with_capacity ( local_tx. htlc_outputs . len ( ) ) ;
@@ -1864,7 +1880,8 @@ impl ChannelMonitor {
1864
1880
htlc_timeout_tx. input [ 0 ] . witness . push ( htlc_script. clone ( ) . into_bytes ( ) ) ;
1865
1881
1866
1882
add_dynamic_output ! ( htlc_timeout_tx, 0 ) ;
1867
- 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 ) ) ) ;
1883
+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1884
+ 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 ) ) ) ;
1868
1885
res. push ( htlc_timeout_tx) ;
1869
1886
} else {
1870
1887
if let Some ( payment_preimage) = self . payment_preimages . get ( & htlc. payment_hash ) {
@@ -1883,7 +1900,8 @@ impl ChannelMonitor {
1883
1900
htlc_success_tx. input [ 0 ] . witness . push ( htlc_script. clone ( ) . into_bytes ( ) ) ;
1884
1901
1885
1902
add_dynamic_output ! ( htlc_success_tx, 0 ) ;
1886
- 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 ) ) ) ;
1903
+ let height_timer = Self :: get_height_timer ( height, htlc. cltv_expiry ) ;
1904
+ 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 ) ) ) ;
1887
1905
res. push ( htlc_success_tx) ;
1888
1906
}
1889
1907
}
@@ -2654,7 +2672,8 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
2654
2672
_ => return Err ( DecodeError :: InvalidValue ) ,
2655
2673
} ;
2656
2674
let last_fee = Readable :: read ( reader) ?;
2657
- our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee) ) ;
2675
+ let timelock_expiration = Readable :: read ( reader) ?;
2676
+ our_claim_txn_waiting_first_conf. insert ( outpoint, ( height_target, tx_material, last_fee, timelock_expiration) ) ;
2658
2677
}
2659
2678
2660
2679
let waiting_threshold_conf_len: u64 = Readable :: read ( reader) ?;
0 commit comments