@@ -934,6 +934,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: WriteableEcdsaChannelSigner> {
934934 /// Ordering of tuple data: (their_per_commitment_point, feerate_per_kw, to_broadcaster_sats,
935935 /// to_countersignatory_sats)
936936 initial_counterparty_commitment_info : Option < ( PublicKey , u32 , u64 , u64 ) > ,
937+
938+ /// The first block height at which we had no remaining claimable balances.
939+ blanaces_empty_height : Option < u32 > ,
937940}
938941
939942/// Transaction outputs to watch for on-chain spends.
@@ -1327,6 +1330,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
13271330 best_block,
13281331 counterparty_node_id : Some ( counterparty_node_id) ,
13291332 initial_counterparty_commitment_info : None ,
1333+ blanaces_empty_height : None ,
13301334 } )
13311335 }
13321336
@@ -1855,6 +1859,45 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
18551859 spendable_outputs
18561860 }
18571861
1862+ /// Checks if the monitor is stale, meaning it has not been updated with a new block data in a
1863+ /// substantial amount of time and thus has no outputs to watch, ie
1864+ /// this monitor is not expected to be able to claim any funds on chain.
1865+ ///
1866+ /// The first time this method is called it will save the current known height of the monitor
1867+ /// if all funds are claimed. Otherwise, if we yet to claim all funds, it will return false. If all funds
1868+ /// are claimed, it will return true if the monitor has not been updated with new block data in
1869+ /// a substantial amount of time referred as `threshold` and `balances_empty_height` is set.
1870+ pub ( crate ) fn is_stale ( & self ) -> bool {
1871+ let threshold = 2016 ; // TODO: Should this be configurable?
1872+ let is_all_funds_claimed = self . get_claimable_balances ( ) . is_empty ( ) ;
1873+ let current_height = self . current_best_block ( ) . height ;
1874+ let inner = self . inner . lock ( ) . unwrap ( ) ;
1875+ let blanaces_empty_height = inner. blanaces_empty_height ;
1876+ if let Some ( blanaces_empty_height) = blanaces_empty_height {
1877+ // This if can be ture at least in the second time this method is called. we check if
1878+ // the monitor has not been updated with new block data to watch new ouputs in a
1879+ // substantial amount(2016 blocks) of time meaning the channel is probably closed and
1880+ // this monitor is not expected to be able to claim any funds on chain.
1881+ debug_assert ! ( is_all_funds_claimed, "Trying to check if monitor is stale before all funds are claimed. Aborting." ) ;
1882+ return current_height > blanaces_empty_height + threshold;
1883+ } else if is_all_funds_claimed {
1884+ // If we claimed all funds, but `balances_empty_height` is None, we set it to the
1885+ // current height and start counting from there.
1886+ // This is to to make sure we don't consider the monitor stale on the first call to
1887+ // `is_stale` after all funds are claimed.
1888+ let mut inner = inner;
1889+ inner. blanaces_empty_height = Some ( current_height) ;
1890+ return false ;
1891+ }
1892+ // We still have funds to claim.
1893+ return false ;
1894+ }
1895+
1896+ #[ cfg( test) ]
1897+ pub fn balances_empty_height ( & self ) -> Option < u32 > {
1898+ self . inner . lock ( ) . unwrap ( ) . blanaces_empty_height
1899+ }
1900+
18581901 #[ cfg( test) ]
18591902 pub fn get_counterparty_payment_script ( & self ) -> ScriptBuf {
18601903 self . inner . lock ( ) . unwrap ( ) . counterparty_payment_script . clone ( )
@@ -4721,6 +4764,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
47214764 best_block,
47224765 counterparty_node_id,
47234766 initial_counterparty_commitment_info,
4767+ blanaces_empty_height : None ,
47244768 } ) ) )
47254769 }
47264770}
0 commit comments