@@ -42,6 +42,8 @@ use std;
42
42
use std:: default:: Default ;
43
43
use std:: { cmp, mem, fmt} ;
44
44
use std:: ops:: Deref ;
45
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
46
+ use std:: sync:: Mutex ;
45
47
use bitcoin:: hashes:: hex:: ToHex ;
46
48
47
49
#[ cfg( test) ]
@@ -386,6 +388,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
386
388
commitment_secrets : CounterpartyCommitmentSecrets ,
387
389
388
390
network_sync : UpdateStatus ,
391
+
392
+ // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
393
+ // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
394
+ // be, by comparing the cached values to the fee of the tranaction generated by
395
+ // `build_commitment_transaction`.
396
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
397
+ next_local_commitment_tx_fee_info_cached : Mutex < Option < CommitmentTxInfoCached > > ,
398
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
399
+ next_remote_commitment_tx_fee_info_cached : Mutex < Option < CommitmentTxInfoCached > > ,
400
+ }
401
+
402
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
403
+ struct CommitmentTxInfoCached {
404
+ fee : u64 ,
405
+ num_htlcs : usize ,
406
+ next_holder_htlc_id : u64 ,
407
+ next_counterparty_htlc_id : u64 ,
408
+ feerate : u32 ,
389
409
}
390
410
391
411
pub const OUR_MAX_HTLCS : u16 = 50 ; //TODO
@@ -557,6 +577,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
557
577
commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
558
578
559
579
network_sync : UpdateStatus :: Fresh ,
580
+
581
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
582
+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
583
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
584
+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
560
585
} )
561
586
}
562
587
@@ -790,6 +815,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
790
815
commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
791
816
792
817
network_sync : UpdateStatus :: Fresh ,
818
+
819
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
820
+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
821
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
822
+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
793
823
} ;
794
824
795
825
Ok ( chan)
@@ -1740,7 +1770,30 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1740
1770
}
1741
1771
}
1742
1772
1743
- self . commit_tx_fee_msat ( included_htlcs + addl_htlcs)
1773
+ let num_htlcs = included_htlcs + addl_htlcs;
1774
+ let res = self . commit_tx_fee_msat ( num_htlcs) ;
1775
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1776
+ {
1777
+ let mut num_htlcs = num_htlcs;
1778
+ let mut fee = res;
1779
+ if fee_spike_buffer_htlc. is_some ( ) {
1780
+ num_htlcs -= 1 ;
1781
+ fee = self . commit_tx_fee_msat ( num_htlcs) ;
1782
+ }
1783
+ let commitment_tx_info = CommitmentTxInfoCached {
1784
+ fee,
1785
+ num_htlcs,
1786
+ next_holder_htlc_id : if locally_offered { self . next_holder_htlc_id + 1 } else {
1787
+ self . next_holder_htlc_id
1788
+ } ,
1789
+ next_counterparty_htlc_id : if locally_offered { self . next_counterparty_htlc_id } else {
1790
+ self . next_counterparty_htlc_id + 1
1791
+ } ,
1792
+ feerate : self . feerate_per_kw ,
1793
+ } ;
1794
+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = Some ( commitment_tx_info) ;
1795
+ }
1796
+ res
1744
1797
}
1745
1798
1746
1799
// Get the commitment tx fee for the remote's next commitment transaction based on the number of
@@ -1781,11 +1834,35 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1781
1834
match htlc. state {
1782
1835
OutboundHTLCState :: Committed => included_htlcs += 1 ,
1783
1836
OutboundHTLCState :: RemoteRemoved { ..} => included_htlcs += 1 ,
1837
+ OutboundHTLCState :: LocalAnnounced { .. } => included_htlcs += 1 ,
1784
1838
_ => { } ,
1785
1839
}
1786
1840
}
1787
1841
1788
- self . commit_tx_fee_msat ( included_htlcs + addl_htlcs)
1842
+ let num_htlcs = included_htlcs + addl_htlcs;
1843
+ let res = self . commit_tx_fee_msat ( num_htlcs) ;
1844
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1845
+ {
1846
+ let mut num_htlcs = num_htlcs;
1847
+ let mut fee = res;
1848
+ if fee_spike_buffer_htlc. is_some ( ) {
1849
+ num_htlcs -= 1 ;
1850
+ fee = self . commit_tx_fee_msat ( num_htlcs) ;
1851
+ }
1852
+ let commitment_tx_info = CommitmentTxInfoCached {
1853
+ fee,
1854
+ num_htlcs,
1855
+ next_holder_htlc_id : if locally_offered { self . next_holder_htlc_id + 1 } else {
1856
+ self . next_holder_htlc_id
1857
+ } ,
1858
+ next_counterparty_htlc_id : if locally_offered { self . next_counterparty_htlc_id } else {
1859
+ self . next_counterparty_htlc_id + 1
1860
+ } ,
1861
+ feerate : self . feerate_per_kw ,
1862
+ } ;
1863
+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = Some ( commitment_tx_info) ;
1864
+ }
1865
+ res
1789
1866
}
1790
1867
1791
1868
pub fn update_add_htlc < F , L : Deref > ( & mut self , msg : & msgs:: UpdateAddHTLC , mut pending_forward_status : PendingHTLCStatus , create_pending_htlc_status : F , logger : & L ) -> Result < ( ) , ChannelError >
@@ -2019,15 +2096,27 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
2019
2096
( commitment_tx. 1 , htlcs_cloned, commitment_tx. 0 , commitment_txid)
2020
2097
} ;
2021
2098
2099
+ let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
2022
2100
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
2023
2101
if update_fee {
2024
- let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
2025
-
2026
2102
let counterparty_reserve_we_require = Channel :: < ChanSigner > :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) ;
2027
2103
if self . channel_value_satoshis - self . value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
2028
2104
return Err ( ( None , ChannelError :: Close ( "Funding remote cannot afford proposed new fee" . to_owned ( ) ) ) ) ;
2029
2105
}
2030
2106
}
2107
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
2108
+ {
2109
+ if self . is_outbound ( ) {
2110
+ let projected_commit_tx_info = self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
2111
+ if let Some ( info) = projected_commit_tx_info {
2112
+ if info. num_htlcs == num_htlcs && info. next_holder_htlc_id == self . next_holder_htlc_id
2113
+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
2114
+ && info. feerate == self . feerate_per_kw {
2115
+ assert_eq ! ( total_fee, info. fee / 1000 ) ;
2116
+ }
2117
+ }
2118
+ }
2119
+ }
2031
2120
2032
2121
if msg. htlc_signatures . len ( ) != num_htlcs {
2033
2122
return Err ( ( None , ChannelError :: Close ( format ! ( "Got wrong number of HTLC signatures ({}) from remote. It must be {}" , msg. htlc_signatures. len( ) , num_htlcs) ) ) ) ;
@@ -3921,6 +4010,22 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
3921
4010
let counterparty_commitment_txid = counterparty_commitment_tx. 0 . trust ( ) . txid ( ) ;
3922
4011
let ( signature, htlc_signatures) ;
3923
4012
4013
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4014
+ {
4015
+ if !self . is_outbound ( ) {
4016
+ let projected_commit_tx_info = self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
4017
+ if let Some ( info) = projected_commit_tx_info {
4018
+ if info. num_htlcs == counterparty_commitment_tx. 1
4019
+ && info. next_holder_htlc_id == self . next_holder_htlc_id
4020
+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
4021
+ && info. feerate == self . feerate_per_kw {
4022
+ let actual_fee = self . commit_tx_fee_msat ( counterparty_commitment_tx. 1 ) ;
4023
+ assert_eq ! ( actual_fee, info. fee) ;
4024
+ }
4025
+ }
4026
+ }
4027
+ }
4028
+
3924
4029
{
3925
4030
let mut htlcs = Vec :: with_capacity ( counterparty_commitment_tx. 2 . len ( ) ) ;
3926
4031
for & ( ref htlc, _) in counterparty_commitment_tx. 2 . iter ( ) {
@@ -4511,6 +4616,11 @@ impl<'a, ChanSigner: ChannelKeys, K: Deref> ReadableArgs<&'a K> for Channel<Chan
4511
4616
commitment_secrets,
4512
4617
4513
4618
network_sync : UpdateStatus :: Fresh ,
4619
+
4620
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4621
+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
4622
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4623
+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
4514
4624
} )
4515
4625
}
4516
4626
}
0 commit comments