@@ -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+ total_pending_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 fee = res;
1778+ if fee_spike_buffer_htlc. is_some ( ) {
1779+ fee = self . commit_tx_fee_msat ( num_htlcs - 1 ) ;
1780+ }
1781+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( )
1782+ + self . holding_cell_htlc_updates . len ( ) ;
1783+ let commitment_tx_info = CommitmentTxInfoCached {
1784+ fee,
1785+ total_pending_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,34 @@ 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 fee = res;
1847+ if fee_spike_buffer_htlc. is_some ( ) {
1848+ fee = self . commit_tx_fee_msat ( num_htlcs - 1 ) ;
1849+ }
1850+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( ) ;
1851+ let commitment_tx_info = CommitmentTxInfoCached {
1852+ fee,
1853+ total_pending_htlcs,
1854+ next_holder_htlc_id : if locally_offered { self . next_holder_htlc_id + 1 } else {
1855+ self . next_holder_htlc_id
1856+ } ,
1857+ next_counterparty_htlc_id : if locally_offered { self . next_counterparty_htlc_id } else {
1858+ self . next_counterparty_htlc_id + 1
1859+ } ,
1860+ feerate : self . feerate_per_kw ,
1861+ } ;
1862+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = Some ( commitment_tx_info) ;
1863+ }
1864+ res
17891865 }
17901866
17911867 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 +2095,31 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
20192095 ( commitment_tx. 1 , htlcs_cloned, commitment_tx. 0 , commitment_txid)
20202096 } ;
20212097
2098+ let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
20222099 //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
20232100 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-
20262101 let counterparty_reserve_we_require = Channel :: < ChanSigner > :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) ;
20272102 if self . channel_value_satoshis - self . value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
20282103 return Err ( ( None , ChannelError :: Close ( "Funding remote cannot afford proposed new fee" . to_owned ( ) ) ) ) ;
20292104 }
20302105 }
2106+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
2107+ {
2108+ if self . is_outbound ( ) {
2109+ let projected_commit_tx_info = self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
2110+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2111+ if let Some ( info) = projected_commit_tx_info {
2112+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( )
2113+ + self . holding_cell_htlc_updates . len ( ) ;
2114+ if info. total_pending_htlcs == total_pending_htlcs
2115+ && info. next_holder_htlc_id == self . next_holder_htlc_id
2116+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
2117+ && info. feerate == self . feerate_per_kw {
2118+ assert_eq ! ( total_fee, info. fee / 1000 ) ;
2119+ }
2120+ }
2121+ }
2122+ }
20312123
20322124 if msg. htlc_signatures . len ( ) != num_htlcs {
20332125 return Err ( ( None , ChannelError :: Close ( format ! ( "Got wrong number of HTLC signatures ({}) from remote. It must be {}" , msg. htlc_signatures. len( ) , num_htlcs) ) ) ) ;
@@ -2293,6 +2385,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
22932385 return Err ( ChannelError :: Close ( "Received an unexpected revoke_and_ack" . to_owned ( ) ) ) ;
22942386 }
22952387
2388+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
2389+ {
2390+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2391+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2392+ }
2393+
22962394 self . commitment_secrets . provide_secret ( self . cur_counterparty_commitment_transaction_number + 1 , msg. per_commitment_secret )
22972395 . map_err ( |_| ChannelError :: Close ( "Previous secrets did not match new one" . to_owned ( ) ) ) ?;
22982396 self . latest_monitor_update_id += 1 ;
@@ -3921,6 +4019,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
39214019 let counterparty_commitment_txid = counterparty_commitment_tx. 0 . trust ( ) . txid ( ) ;
39224020 let ( signature, htlc_signatures) ;
39234021
4022+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4023+ {
4024+ if !self . is_outbound ( ) {
4025+ let projected_commit_tx_info = self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
4026+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
4027+ if let Some ( info) = projected_commit_tx_info {
4028+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( ) ;
4029+ if info. total_pending_htlcs == total_pending_htlcs
4030+ && info. next_holder_htlc_id == self . next_holder_htlc_id
4031+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
4032+ && info. feerate == self . feerate_per_kw {
4033+ let actual_fee = self . commit_tx_fee_msat ( counterparty_commitment_tx. 1 ) ;
4034+ assert_eq ! ( actual_fee, info. fee) ;
4035+ }
4036+ }
4037+ }
4038+ }
4039+
39244040 {
39254041 let mut htlcs = Vec :: with_capacity ( counterparty_commitment_tx. 2 . len ( ) ) ;
39264042 for & ( ref htlc, _) in counterparty_commitment_tx. 2 . iter ( ) {
@@ -4511,6 +4627,11 @@ impl<'a, ChanSigner: ChannelKeys, K: Deref> ReadableArgs<&'a K> for Channel<Chan
45114627 commitment_secrets,
45124628
45134629 network_sync : UpdateStatus :: Fresh ,
4630+
4631+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4632+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
4633+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4634+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
45144635 } )
45154636 }
45164637}
0 commit comments