Skip to content

Commit 4005724

Browse files
authored
Merge pull request #1663 from tnull/2022-08-drop-register-output-return
Drop return value from `Filter::register_output`
2 parents ca4e31d + c562f33 commit 4005724

File tree

3 files changed

+65
-194
lines changed

3 files changed

+65
-194
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 51 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -263,82 +263,67 @@ where C::Target: chain::Filter,
263263
where
264264
FN: Fn(&ChannelMonitor<ChannelSigner>, &TransactionData) -> Vec<TransactionOutputs>
265265
{
266-
let mut dependent_txdata = Vec::new();
267-
{
268-
let monitor_states = self.monitors.write().unwrap();
269-
if let Some(height) = best_height {
270-
// If the best block height is being updated, update highest_chain_height under the
271-
// monitors write lock.
272-
let old_height = self.highest_chain_height.load(Ordering::Acquire);
273-
let new_height = height as usize;
274-
if new_height > old_height {
275-
self.highest_chain_height.store(new_height, Ordering::Release);
276-
}
266+
let monitor_states = self.monitors.write().unwrap();
267+
if let Some(height) = best_height {
268+
// If the best block height is being updated, update highest_chain_height under the
269+
// monitors write lock.
270+
let old_height = self.highest_chain_height.load(Ordering::Acquire);
271+
let new_height = height as usize;
272+
if new_height > old_height {
273+
self.highest_chain_height.store(new_height, Ordering::Release);
277274
}
275+
}
278276

279-
for (funding_outpoint, monitor_state) in monitor_states.iter() {
280-
let monitor = &monitor_state.monitor;
281-
let mut txn_outputs;
282-
{
283-
txn_outputs = process(monitor, txdata);
284-
let update_id = MonitorUpdateId {
285-
contents: UpdateOrigin::ChainSync(self.sync_persistence_id.get_increment()),
286-
};
287-
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
288-
if let Some(height) = best_height {
289-
if !monitor_state.has_pending_chainsync_updates(&pending_monitor_updates) {
290-
// If there are not ChainSync persists awaiting completion, go ahead and
291-
// set last_chain_persist_height here - we wouldn't want the first
292-
// TemporaryFailure to always immediately be considered "overly delayed".
293-
monitor_state.last_chain_persist_height.store(height as usize, Ordering::Release);
294-
}
277+
for (funding_outpoint, monitor_state) in monitor_states.iter() {
278+
let monitor = &monitor_state.monitor;
279+
let mut txn_outputs;
280+
{
281+
txn_outputs = process(monitor, txdata);
282+
let update_id = MonitorUpdateId {
283+
contents: UpdateOrigin::ChainSync(self.sync_persistence_id.get_increment()),
284+
};
285+
let mut pending_monitor_updates = monitor_state.pending_monitor_updates.lock().unwrap();
286+
if let Some(height) = best_height {
287+
if !monitor_state.has_pending_chainsync_updates(&pending_monitor_updates) {
288+
// If there are not ChainSync persists awaiting completion, go ahead and
289+
// set last_chain_persist_height here - we wouldn't want the first
290+
// TemporaryFailure to always immediately be considered "overly delayed".
291+
monitor_state.last_chain_persist_height.store(height as usize, Ordering::Release);
295292
}
293+
}
296294

297-
log_trace!(self.logger, "Syncing Channel Monitor for channel {}", log_funding_info!(monitor));
298-
match self.persister.update_persisted_channel(*funding_outpoint, &None, monitor, update_id) {
299-
Ok(()) =>
300-
log_trace!(self.logger, "Finished syncing Channel Monitor for channel {}", log_funding_info!(monitor)),
301-
Err(ChannelMonitorUpdateErr::PermanentFailure) => {
302-
monitor_state.channel_perm_failed.store(true, Ordering::Release);
303-
self.pending_monitor_events.lock().unwrap().push((*funding_outpoint, vec![MonitorEvent::UpdateFailed(*funding_outpoint)], monitor.get_counterparty_node_id()));
304-
},
305-
Err(ChannelMonitorUpdateErr::TemporaryFailure) => {
306-
log_debug!(self.logger, "Channel Monitor sync for channel {} in progress, holding events until completion!", log_funding_info!(monitor));
307-
pending_monitor_updates.push(update_id);
308-
},
309-
}
295+
log_trace!(self.logger, "Syncing Channel Monitor for channel {}", log_funding_info!(monitor));
296+
match self.persister.update_persisted_channel(*funding_outpoint, &None, monitor, update_id) {
297+
Ok(()) =>
298+
log_trace!(self.logger, "Finished syncing Channel Monitor for channel {}", log_funding_info!(monitor)),
299+
Err(ChannelMonitorUpdateErr::PermanentFailure) => {
300+
monitor_state.channel_perm_failed.store(true, Ordering::Release);
301+
self.pending_monitor_events.lock().unwrap().push((*funding_outpoint, vec![MonitorEvent::UpdateFailed(*funding_outpoint)], monitor.get_counterparty_node_id()));
302+
},
303+
Err(ChannelMonitorUpdateErr::TemporaryFailure) => {
304+
log_debug!(self.logger, "Channel Monitor sync for channel {} in progress, holding events until completion!", log_funding_info!(monitor));
305+
pending_monitor_updates.push(update_id);
306+
},
310307
}
308+
}
311309

312-
// Register any new outputs with the chain source for filtering, storing any dependent
313-
// transactions from within the block that previously had not been included in txdata.
314-
if let Some(ref chain_source) = self.chain_source {
315-
let block_hash = header.block_hash();
316-
for (txid, mut outputs) in txn_outputs.drain(..) {
317-
for (idx, output) in outputs.drain(..) {
318-
// Register any new outputs with the chain source for filtering and recurse
319-
// if it indicates that there are dependent transactions within the block
320-
// that had not been previously included in txdata.
321-
let output = WatchedOutput {
322-
block_hash: Some(block_hash),
323-
outpoint: OutPoint { txid, index: idx as u16 },
324-
script_pubkey: output.script_pubkey,
325-
};
326-
if let Some(tx) = chain_source.register_output(output) {
327-
dependent_txdata.push(tx);
328-
}
329-
}
310+
// Register any new outputs with the chain source for filtering, storing any dependent
311+
// transactions from within the block that previously had not been included in txdata.
312+
if let Some(ref chain_source) = self.chain_source {
313+
let block_hash = header.block_hash();
314+
for (txid, mut outputs) in txn_outputs.drain(..) {
315+
for (idx, output) in outputs.drain(..) {
316+
// Register any new outputs with the chain source for filtering
317+
let output = WatchedOutput {
318+
block_hash: Some(block_hash),
319+
outpoint: OutPoint { txid, index: idx as u16 },
320+
script_pubkey: output.script_pubkey,
321+
};
322+
chain_source.register_output(output)
330323
}
331324
}
332325
}
333326
}
334-
335-
// Recursively call for any dependent transactions that were identified by the chain source.
336-
if !dependent_txdata.is_empty() {
337-
dependent_txdata.sort_unstable_by_key(|(index, _tx)| *index);
338-
dependent_txdata.dedup_by_key(|(index, _tx)| *index);
339-
let txdata: Vec<_> = dependent_txdata.iter().map(|(index, tx)| (*index, tx)).collect();
340-
self.process_chain_data(header, None, &txdata, process); // We skip the best height the second go-around
341-
}
342327
}
343328

344329
/// Creates a new `ChainMonitor` used to watch on-chain activity pertaining to channels.
@@ -746,50 +731,6 @@ mod tests {
746731
use ln::msgs::ChannelMessageHandler;
747732
use util::errors::APIError;
748733
use util::events::{ClosureReason, MessageSendEvent, MessageSendEventsProvider};
749-
use util::test_utils::{OnRegisterOutput, TxOutReference};
750-
751-
/// Tests that in-block dependent transactions are processed by `block_connected` when not
752-
/// included in `txdata` but returned by [`chain::Filter::register_output`]. For instance,
753-
/// a (non-anchor) commitment transaction's HTLC output may be spent in the same block as the
754-
/// commitment transaction itself. An Electrum client may filter the commitment transaction but
755-
/// needs to return the HTLC transaction so it can be processed.
756-
#[test]
757-
fn connect_block_checks_dependent_transactions() {
758-
let chanmon_cfgs = create_chanmon_cfgs(2);
759-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
760-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
761-
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
762-
let channel = create_announced_chan_between_nodes(
763-
&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
764-
765-
// Send a payment, saving nodes[0]'s revoked commitment and HTLC-Timeout transactions.
766-
let (commitment_tx, htlc_tx) = {
767-
let payment_preimage = route_payment(&nodes[0], &vec!(&nodes[1])[..], 5_000_000).0;
768-
let mut txn = get_local_commitment_txn!(nodes[0], channel.2);
769-
claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage);
770-
771-
assert_eq!(txn.len(), 2);
772-
(txn.remove(0), txn.remove(0))
773-
};
774-
775-
// Set expectations on nodes[1]'s chain source to return dependent transactions.
776-
let htlc_output = TxOutReference(commitment_tx.clone(), 0);
777-
let to_local_output = TxOutReference(commitment_tx.clone(), 1);
778-
let htlc_timeout_output = TxOutReference(htlc_tx.clone(), 0);
779-
nodes[1].chain_source
780-
.expect(OnRegisterOutput { with: htlc_output, returns: Some((1, htlc_tx)) })
781-
.expect(OnRegisterOutput { with: to_local_output, returns: None })
782-
.expect(OnRegisterOutput { with: htlc_timeout_output, returns: None });
783-
784-
// Notify nodes[1] that nodes[0]'s revoked commitment transaction was mined. The chain
785-
// source should return the dependent HTLC transaction when the HTLC output is registered.
786-
mine_transaction(&nodes[1], &commitment_tx);
787-
788-
// Clean up so uninteresting assertions don't fail.
789-
check_added_monitors!(nodes[1], 1);
790-
nodes[1].node.get_and_clear_pending_msg_events();
791-
nodes[1].node.get_and_clear_pending_events();
792-
}
793734

794735
#[test]
795736
fn test_async_ooo_offchain_updates() {

lightning/src/chain/mod.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use bitcoin::blockdata::block::{Block, BlockHeader};
1313
use bitcoin::blockdata::constants::genesis_block;
1414
use bitcoin::blockdata::script::Script;
15-
use bitcoin::blockdata::transaction::{Transaction, TxOut};
15+
use bitcoin::blockdata::transaction::TxOut;
1616
use bitcoin::hash_types::{BlockHash, Txid};
1717
use bitcoin::network::constants::Network;
1818
use bitcoin::secp256k1::PublicKey;
@@ -151,15 +151,15 @@ pub trait Confirm {
151151
/// in the event of a chain reorganization, it must not be called with a `header` that is no
152152
/// longer in the chain as of the last call to [`best_block_updated`].
153153
///
154-
/// [chain order]: Confirm#Order
154+
/// [chain order]: Confirm#order
155155
/// [`best_block_updated`]: Self::best_block_updated
156156
fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32);
157157

158158
/// Processes a transaction that is no longer confirmed as result of a chain reorganization.
159159
///
160160
/// Should be called for any transaction returned by [`get_relevant_txids`] if it has been
161-
/// reorganized out of the best chain. Once called, the given transaction should not be returned
162-
/// by [`get_relevant_txids`] unless it has been reconfirmed via [`transactions_confirmed`].
161+
/// reorganized out of the best chain. Once called, the given transaction will not be returned
162+
/// by [`get_relevant_txids`], unless it has been reconfirmed via [`transactions_confirmed`].
163163
///
164164
/// [`get_relevant_txids`]: Self::get_relevant_txids
165165
/// [`transactions_confirmed`]: Self::transactions_confirmed
@@ -173,9 +173,9 @@ pub trait Confirm {
173173

174174
/// Returns transactions that should be monitored for reorganization out of the chain.
175175
///
176-
/// Should include any transactions passed to [`transactions_confirmed`] that have insufficient
177-
/// confirmations to be safe from a chain reorganization. Should not include any transactions
178-
/// passed to [`transaction_unconfirmed`] unless later reconfirmed.
176+
/// Will include any transactions passed to [`transactions_confirmed`] that have insufficient
177+
/// confirmations to be safe from a chain reorganization. Will not include any transactions
178+
/// passed to [`transaction_unconfirmed`], unless later reconfirmed.
179179
///
180180
/// May be called to determine the subset of transactions that must still be monitored for
181181
/// reorganization. Will be idempotent between calls but may change as a result of calls to the
@@ -333,21 +333,18 @@ pub trait Filter {
333333

334334
/// Registers interest in spends of a transaction output.
335335
///
336-
/// Optionally, when `output.block_hash` is set, should return any transaction spending the
337-
/// output that is found in the corresponding block along with its index.
338-
///
339-
/// This return value is useful for Electrum clients in order to supply in-block descendant
340-
/// transactions which otherwise were not included. This is not necessary for other clients if
341-
/// such descendant transactions were already included (e.g., when a BIP 157 client provides the
342-
/// full block).
343-
fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)>;
336+
/// Note that this method might be called during processing of a new block. You therefore need
337+
/// to ensure that also dependent output spents within an already connected block are correctly
338+
/// handled, e.g., by re-scanning the block in question whenever new outputs have been
339+
/// registered mid-processing.
340+
fn register_output(&self, output: WatchedOutput);
344341
}
345342

346343
/// A transaction output watched by a [`ChannelMonitor`] for spends on-chain.
347344
///
348345
/// Used to convey to a [`Filter`] such an output with a given spending condition. Any transaction
349346
/// spending the output must be given to [`ChannelMonitor::block_connected`] either directly or via
350-
/// the return value of [`Filter::register_output`].
347+
/// [`Confirm::transactions_confirmed`].
351348
///
352349
/// If `block_hash` is `Some`, this indicates the output was created in the corresponding block and
353350
/// may have been spent there. See [`Filter::register_output`] for details.

lightning/src/util/test_utils.rs

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,6 @@ pub struct TestChainSource {
730730
pub utxo_ret: Mutex<Result<TxOut, chain::AccessError>>,
731731
pub watched_txn: Mutex<HashSet<(Txid, Script)>>,
732732
pub watched_outputs: Mutex<HashSet<(OutPoint, Script)>>,
733-
expectations: Mutex<Option<VecDeque<OnRegisterOutput>>>,
734733
}
735734

736735
impl TestChainSource {
@@ -741,17 +740,8 @@ impl TestChainSource {
741740
utxo_ret: Mutex::new(Ok(TxOut { value: u64::max_value(), script_pubkey })),
742741
watched_txn: Mutex::new(HashSet::new()),
743742
watched_outputs: Mutex::new(HashSet::new()),
744-
expectations: Mutex::new(None),
745743
}
746744
}
747-
748-
/// Sets an expectation that [`chain::Filter::register_output`] is called.
749-
pub fn expect(&self, expectation: OnRegisterOutput) -> &Self {
750-
self.expectations.lock().unwrap()
751-
.get_or_insert_with(|| VecDeque::new())
752-
.push_back(expectation);
753-
self
754-
}
755745
}
756746

757747
impl chain::Access for TestChainSource {
@@ -769,24 +759,8 @@ impl chain::Filter for TestChainSource {
769759
self.watched_txn.lock().unwrap().insert((*txid, script_pubkey.clone()));
770760
}
771761

772-
fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)> {
773-
let dependent_tx = match &mut *self.expectations.lock().unwrap() {
774-
None => None,
775-
Some(expectations) => match expectations.pop_front() {
776-
None => {
777-
panic!("Unexpected register_output: {:?}",
778-
(output.outpoint, output.script_pubkey));
779-
},
780-
Some(expectation) => {
781-
assert_eq!(output.outpoint, expectation.outpoint());
782-
assert_eq!(&output.script_pubkey, expectation.script_pubkey());
783-
expectation.returns
784-
},
785-
},
786-
};
787-
762+
fn register_output(&self, output: WatchedOutput) {
788763
self.watched_outputs.lock().unwrap().insert((output.outpoint, output.script_pubkey));
789-
dependent_tx
790764
}
791765
}
792766

@@ -795,47 +769,6 @@ impl Drop for TestChainSource {
795769
if panicking() {
796770
return;
797771
}
798-
799-
if let Some(expectations) = &*self.expectations.lock().unwrap() {
800-
if !expectations.is_empty() {
801-
panic!("Unsatisfied expectations: {:?}", expectations);
802-
}
803-
}
804-
}
805-
}
806-
807-
/// An expectation that [`chain::Filter::register_output`] was called with a transaction output and
808-
/// returns an optional dependent transaction that spends the output in the same block.
809-
pub struct OnRegisterOutput {
810-
/// The transaction output to register.
811-
pub with: TxOutReference,
812-
813-
/// A dependent transaction spending the output along with its position in the block.
814-
pub returns: Option<(usize, Transaction)>,
815-
}
816-
817-
/// A transaction output as identified by an index into a transaction's output list.
818-
pub struct TxOutReference(pub Transaction, pub usize);
819-
820-
impl OnRegisterOutput {
821-
fn outpoint(&self) -> OutPoint {
822-
let txid = self.with.0.txid();
823-
let index = self.with.1 as u16;
824-
OutPoint { txid, index }
825-
}
826-
827-
fn script_pubkey(&self) -> &Script {
828-
let index = self.with.1;
829-
&self.with.0.output[index].script_pubkey
830-
}
831-
}
832-
833-
impl core::fmt::Debug for OnRegisterOutput {
834-
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
835-
f.debug_struct("OnRegisterOutput")
836-
.field("outpoint", &self.outpoint())
837-
.field("script_pubkey", self.script_pubkey())
838-
.finish()
839772
}
840773
}
841774

0 commit comments

Comments
 (0)