@@ -42,6 +42,8 @@ use std;
4242use std:: default:: Default ;
4343use std:: { cmp, mem, fmt} ;
4444use std:: ops:: Deref ;
45+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
46+ use std:: sync:: Mutex ;
4547use bitcoin:: hashes:: hex:: ToHex ;
4648
4749#[ cfg( test) ]
@@ -386,6 +388,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
386388 commitment_secrets : CounterpartyCommitmentSecrets ,
387389
388390 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 ,
389409}
390410
391411pub const OUR_MAX_HTLCS : u16 = 50 ; //TODO
@@ -557,6 +577,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
557577 commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
558578
559579 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 ) ,
560585 } )
561586 }
562587
@@ -790,6 +815,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
790815 commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
791816
792817 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 ) ,
793823 } ;
794824
795825 Ok ( chan)
@@ -1740,7 +1770,30 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17401770 }
17411771 }
17421772
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
17441797 }
17451798
17461799 // 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> {
17811834 match htlc. state {
17821835 OutboundHTLCState :: Committed => included_htlcs += 1 ,
17831836 OutboundHTLCState :: RemoteRemoved { ..} => included_htlcs += 1 ,
1837+ OutboundHTLCState :: LocalAnnounced { .. } => included_htlcs += 1 ,
17841838 _ => { } ,
17851839 }
17861840 }
17871841
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
17891866 }
17901867
17911868 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> {
20192096 ( commitment_tx. 1 , htlcs_cloned, commitment_tx. 0 , commitment_txid)
20202097 } ;
20212098
2099+ let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
20222100 //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
20232101 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-
20262102 let counterparty_reserve_we_require = Channel :: < ChanSigner > :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) ;
20272103 if self . channel_value_satoshis - self . value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
20282104 return Err ( ( None , ChannelError :: Close ( "Funding remote cannot afford proposed new fee" . to_owned ( ) ) ) ) ;
20292105 }
20302106 }
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+ }
20312120
20322121 if msg. htlc_signatures . len ( ) != num_htlcs {
20332122 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> {
39214010 let counterparty_commitment_txid = counterparty_commitment_tx. 0 . trust ( ) . txid ( ) ;
39224011 let ( signature, htlc_signatures) ;
39234012
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+
39244029 {
39254030 let mut htlcs = Vec :: with_capacity ( counterparty_commitment_tx. 2 . len ( ) ) ;
39264031 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
45114616 commitment_secrets,
45124617
45134618 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 ) ,
45144624 } )
45154625 }
45164626}
0 commit comments