@@ -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) ]
@@ -407,6 +409,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
407409 commitment_secrets : CounterpartyCommitmentSecrets ,
408410
409411 network_sync : UpdateStatus ,
412+
413+ // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
414+ // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
415+ // be, by comparing the cached values to the fee of the tranaction generated by
416+ // `build_commitment_transaction`.
417+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
418+ next_local_commitment_tx_fee_info_cached : Mutex < Option < CommitmentTxInfoCached > > ,
419+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
420+ next_remote_commitment_tx_fee_info_cached : Mutex < Option < CommitmentTxInfoCached > > ,
421+ }
422+
423+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
424+ struct CommitmentTxInfoCached {
425+ fee : u64 ,
426+ total_pending_htlcs : usize ,
427+ next_holder_htlc_id : u64 ,
428+ next_counterparty_htlc_id : u64 ,
429+ feerate : u32 ,
410430}
411431
412432pub const OUR_MAX_HTLCS : u16 = 50 ; //TODO
@@ -578,6 +598,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
578598 commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
579599
580600 network_sync : UpdateStatus :: Fresh ,
601+
602+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
603+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
604+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
605+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
581606 } )
582607 }
583608
@@ -811,6 +836,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
811836 commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
812837
813838 network_sync : UpdateStatus :: Fresh ,
839+
840+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
841+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
842+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
843+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
814844 } ;
815845
816846 Ok ( chan)
@@ -1768,7 +1798,32 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17681798 }
17691799 }
17701800
1771- self . commit_tx_fee_msat ( included_htlcs + addl_htlcs)
1801+ let num_htlcs = included_htlcs + addl_htlcs;
1802+ let res = self . commit_tx_fee_msat ( num_htlcs) ;
1803+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1804+ {
1805+ let mut fee = res;
1806+ if fee_spike_buffer_htlc. is_some ( ) {
1807+ fee = self . commit_tx_fee_msat ( num_htlcs - 1 ) ;
1808+ }
1809+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( )
1810+ + self . holding_cell_htlc_updates . len ( ) ;
1811+ let commitment_tx_info = CommitmentTxInfoCached {
1812+ fee,
1813+ total_pending_htlcs,
1814+ next_holder_htlc_id : match htlc. origin {
1815+ HTLCInitiator :: LocalOffered => self . next_holder_htlc_id + 1 ,
1816+ HTLCInitiator :: RemoteOffered => self . next_holder_htlc_id ,
1817+ } ,
1818+ next_counterparty_htlc_id : match htlc. origin {
1819+ HTLCInitiator :: LocalOffered => self . next_counterparty_htlc_id ,
1820+ HTLCInitiator :: RemoteOffered => self . next_counterparty_htlc_id + 1 ,
1821+ } ,
1822+ feerate : self . feerate_per_kw ,
1823+ } ;
1824+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = Some ( commitment_tx_info) ;
1825+ }
1826+ res
17721827 }
17731828
17741829 // Get the commitment tx fee for the remote's next commitment transaction based on the number of
@@ -1816,11 +1871,36 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
18161871 match htlc. state {
18171872 OutboundHTLCState :: Committed => included_htlcs += 1 ,
18181873 OutboundHTLCState :: RemoteRemoved { ..} => included_htlcs += 1 ,
1874+ OutboundHTLCState :: LocalAnnounced { .. } => included_htlcs += 1 ,
18191875 _ => { } ,
18201876 }
18211877 }
18221878
1823- self . commit_tx_fee_msat ( included_htlcs + addl_htlcs)
1879+ let num_htlcs = included_htlcs + addl_htlcs;
1880+ let res = self . commit_tx_fee_msat ( num_htlcs) ;
1881+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1882+ {
1883+ let mut fee = res;
1884+ if fee_spike_buffer_htlc. is_some ( ) {
1885+ fee = self . commit_tx_fee_msat ( num_htlcs - 1 ) ;
1886+ }
1887+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( ) ;
1888+ let commitment_tx_info = CommitmentTxInfoCached {
1889+ fee,
1890+ total_pending_htlcs,
1891+ next_holder_htlc_id : match htlc. origin {
1892+ HTLCInitiator :: LocalOffered => self . next_holder_htlc_id + 1 ,
1893+ HTLCInitiator :: RemoteOffered => self . next_holder_htlc_id ,
1894+ } ,
1895+ next_counterparty_htlc_id : match htlc. origin {
1896+ HTLCInitiator :: LocalOffered => self . next_counterparty_htlc_id ,
1897+ HTLCInitiator :: RemoteOffered => self . next_counterparty_htlc_id + 1 ,
1898+ } ,
1899+ feerate : self . feerate_per_kw ,
1900+ } ;
1901+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = Some ( commitment_tx_info) ;
1902+ }
1903+ res
18241904 }
18251905
18261906 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 >
@@ -2057,15 +2137,31 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
20572137 ( commitment_tx. 1 , htlcs_cloned, commitment_tx. 0 , commitment_txid)
20582138 } ;
20592139
2140+ let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
20602141 //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
20612142 if update_fee {
2062- let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
2063-
20642143 let counterparty_reserve_we_require = Channel :: < ChanSigner > :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) ;
20652144 if self . channel_value_satoshis - self . value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
20662145 return Err ( ( None , ChannelError :: Close ( "Funding remote cannot afford proposed new fee" . to_owned ( ) ) ) ) ;
20672146 }
20682147 }
2148+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
2149+ {
2150+ if self . is_outbound ( ) {
2151+ let projected_commit_tx_info = self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
2152+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2153+ if let Some ( info) = projected_commit_tx_info {
2154+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( )
2155+ + self . holding_cell_htlc_updates . len ( ) ;
2156+ if info. total_pending_htlcs == total_pending_htlcs
2157+ && info. next_holder_htlc_id == self . next_holder_htlc_id
2158+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
2159+ && info. feerate == self . feerate_per_kw {
2160+ assert_eq ! ( total_fee, info. fee / 1000 ) ;
2161+ }
2162+ }
2163+ }
2164+ }
20692165
20702166 if msg. htlc_signatures . len ( ) != num_htlcs {
20712167 return Err ( ( None , ChannelError :: Close ( format ! ( "Got wrong number of HTLC signatures ({}) from remote. It must be {}" , msg. htlc_signatures. len( ) , num_htlcs) ) ) ) ;
@@ -2331,6 +2427,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
23312427 return Err ( ChannelError :: Close ( "Received an unexpected revoke_and_ack" . to_owned ( ) ) ) ;
23322428 }
23332429
2430+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
2431+ {
2432+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2433+ * self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
2434+ }
2435+
23342436 self . commitment_secrets . provide_secret ( self . cur_counterparty_commitment_transaction_number + 1 , msg. per_commitment_secret )
23352437 . map_err ( |_| ChannelError :: Close ( "Previous secrets did not match new one" . to_owned ( ) ) ) ?;
23362438 self . latest_monitor_update_id += 1 ;
@@ -3961,6 +4063,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
39614063 let counterparty_commitment_txid = counterparty_commitment_tx. 0 . trust ( ) . txid ( ) ;
39624064 let ( signature, htlc_signatures) ;
39634065
4066+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4067+ {
4068+ if !self . is_outbound ( ) {
4069+ let projected_commit_tx_info = self . next_remote_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) . take ( ) ;
4070+ * self . next_local_commitment_tx_fee_info_cached . lock ( ) . unwrap ( ) = None ;
4071+ if let Some ( info) = projected_commit_tx_info {
4072+ let total_pending_htlcs = self . pending_inbound_htlcs . len ( ) + self . pending_outbound_htlcs . len ( ) ;
4073+ if info. total_pending_htlcs == total_pending_htlcs
4074+ && info. next_holder_htlc_id == self . next_holder_htlc_id
4075+ && info. next_counterparty_htlc_id == self . next_counterparty_htlc_id
4076+ && info. feerate == self . feerate_per_kw {
4077+ let actual_fee = self . commit_tx_fee_msat ( counterparty_commitment_tx. 1 ) ;
4078+ assert_eq ! ( actual_fee, info. fee) ;
4079+ }
4080+ }
4081+ }
4082+ }
4083+
39644084 {
39654085 let mut htlcs = Vec :: with_capacity ( counterparty_commitment_tx. 2 . len ( ) ) ;
39664086 for & ( ref htlc, _) in counterparty_commitment_tx. 2 . iter ( ) {
@@ -4551,6 +4671,11 @@ impl<'a, ChanSigner: ChannelKeys, K: Deref> ReadableArgs<&'a K> for Channel<Chan
45514671 commitment_secrets,
45524672
45534673 network_sync : UpdateStatus :: Fresh ,
4674+
4675+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4676+ next_local_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
4677+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4678+ next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
45544679 } )
45554680 }
45564681}
0 commit comments