@@ -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) ]
@@ -407,6 +409,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
407
409
commitment_secrets : CounterpartyCommitmentSecrets ,
408
410
409
411
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 ,
410
430
}
411
431
412
432
pub const OUR_MAX_HTLCS : u16 = 50 ; //TODO
@@ -578,6 +598,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
578
598
commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
579
599
580
600
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 ) ,
581
606
} )
582
607
}
583
608
@@ -811,6 +836,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
811
836
commitment_secrets : CounterpartyCommitmentSecrets :: new ( ) ,
812
837
813
838
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 ) ,
814
844
} ;
815
845
816
846
Ok ( chan)
@@ -1768,7 +1798,32 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
1768
1798
}
1769
1799
}
1770
1800
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
1772
1827
}
1773
1828
1774
1829
// 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> {
1816
1871
match htlc. state {
1817
1872
OutboundHTLCState :: Committed => included_htlcs += 1 ,
1818
1873
OutboundHTLCState :: RemoteRemoved { ..} => included_htlcs += 1 ,
1874
+ OutboundHTLCState :: LocalAnnounced { .. } => included_htlcs += 1 ,
1819
1875
_ => { } ,
1820
1876
}
1821
1877
}
1822
1878
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
1824
1904
}
1825
1905
1826
1906
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> {
2057
2137
( commitment_tx. 1 , htlcs_cloned, commitment_tx. 0 , commitment_txid)
2058
2138
} ;
2059
2139
2140
+ let total_fee = feerate_per_kw as u64 * ( COMMITMENT_TX_BASE_WEIGHT + ( num_htlcs as u64 ) * COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
2060
2141
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
2061
2142
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
-
2064
2143
let counterparty_reserve_we_require = Channel :: < ChanSigner > :: get_holder_selected_channel_reserve_satoshis ( self . channel_value_satoshis ) ;
2065
2144
if self . channel_value_satoshis - self . value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
2066
2145
return Err ( ( None , ChannelError :: Close ( "Funding remote cannot afford proposed new fee" . to_owned ( ) ) ) ) ;
2067
2146
}
2068
2147
}
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
+ }
2069
2165
2070
2166
if msg. htlc_signatures . len ( ) != num_htlcs {
2071
2167
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> {
2331
2427
return Err ( ChannelError :: Close ( "Received an unexpected revoke_and_ack" . to_owned ( ) ) ) ;
2332
2428
}
2333
2429
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
+
2334
2436
self . commitment_secrets . provide_secret ( self . cur_counterparty_commitment_transaction_number + 1 , msg. per_commitment_secret )
2335
2437
. map_err ( |_| ChannelError :: Close ( "Previous secrets did not match new one" . to_owned ( ) ) ) ?;
2336
2438
self . latest_monitor_update_id += 1 ;
@@ -3961,6 +4063,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
3961
4063
let counterparty_commitment_txid = counterparty_commitment_tx. 0 . trust ( ) . txid ( ) ;
3962
4064
let ( signature, htlc_signatures) ;
3963
4065
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
+
3964
4084
{
3965
4085
let mut htlcs = Vec :: with_capacity ( counterparty_commitment_tx. 2 . len ( ) ) ;
3966
4086
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
4551
4671
commitment_secrets,
4552
4672
4553
4673
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 ) ,
4554
4679
} )
4555
4680
}
4556
4681
}
0 commit comments