Skip to content

Commit 02b85fa

Browse files
committed
Include block hash for watched transaction output
When registering a watched transaction output, any in-block descendant transactions spending the output must be supplied. Give the block hash when registering such outputs such that this is possible. Otherwise, spends from other blocks may be returned inadvertently.
1 parent d70fdd3 commit 02b85fa

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
use bitcoin::blockdata::block::{Block, BlockHeader};
2727

2828
use chain;
29-
use chain::Filter;
29+
use chain::{Filter, WatchedOutput};
3030
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
3131
use chain::channelmonitor;
3232
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, MonitorEvent, Persist};
@@ -87,9 +87,14 @@ where C::Target: chain::Filter,
8787
let mut txn_outputs = monitor.block_connected(header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
8888

8989
if let Some(ref chain_source) = self.chain_source {
90+
let block_hash = header.block_hash();
9091
for (txid, outputs) in txn_outputs.drain(..) {
9192
for (idx, output) in outputs.iter() {
92-
chain_source.register_output(&OutPoint { txid, index: *idx as u16 }, &output.script_pubkey);
93+
chain_source.register_output(WatchedOutput {
94+
block_hash: Some(block_hash),
95+
outpoint: OutPoint { txid, index: *idx as u16 },
96+
script_pubkey: output.script_pubkey.clone(),
97+
});
9398
}
9499
}
95100
}

lightning/src/chain/channelmonitor.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLC
4040
use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
4141
use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
4242
use chain;
43+
use chain::WatchedOutput;
4344
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
4445
use chain::transaction::{OutPoint, TransactionData};
4546
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
@@ -1174,7 +1175,11 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
11741175
for (txid, outputs) in lock.get_outputs_to_watch().iter() {
11751176
for (index, script_pubkey) in outputs.iter() {
11761177
assert!(*index <= u16::max_value() as u32);
1177-
filter.register_output(&OutPoint { txid: *txid, index: *index as u16 }, script_pubkey);
1178+
filter.register_output(WatchedOutput {
1179+
block_hash: None,
1180+
outpoint: OutPoint { txid: *txid, index: *index as u16 },
1181+
script_pubkey: script_pubkey.clone(),
1182+
});
11781183
}
11791184
}
11801185
}

lightning/src/chain/mod.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,38 @@ pub trait Filter: Send + Sync {
129129
/// a spending condition.
130130
fn register_tx(&self, txid: &Txid, script_pubkey: &Script);
131131

132-
/// Registers interest in spends of a transaction output identified by `outpoint` having
133-
/// `script_pubkey` as the spending condition.
132+
/// Registers interest in spends of a transaction output.
134133
///
135-
/// Optionally, returns any transaction dependent on the output. This is useful for Electrum
136-
/// clients to facilitate registering in-block descendants.
137-
fn register_output(&self, outpoint: &OutPoint, script_pubkey: &Script) -> Option<(usize, Transaction)>;
134+
/// Optionally, when `output.block_hash` is set, should return any transaction spending the
135+
/// output that is found in the corresponding block along with its index.
136+
///
137+
/// This return value is useful for Electrum clients in order to supply in-block descendant
138+
/// transactions which otherwise were not included. This is not necessary for other clients if
139+
/// such descendant transactions were already included (e.g., when a BIP 157 client provides the
140+
/// full block).
141+
fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)>;
142+
}
143+
144+
/// A transaction output watched by a [`ChannelMonitor`] for spends on-chain.
145+
///
146+
/// Used to convey to a [`Filter`] such an output with a given spending condition. Any transaction
147+
/// spending the output must be given to [`ChannelMonitor::block_connected`] either directly or via
148+
/// the return value of [`Filter::register_output`].
149+
///
150+
/// If `block_hash` is `Some`, this indicates the output was created in the corresponding block and
151+
/// may have been spent there. See [`Filter::register_output`] for details.
152+
///
153+
/// [`ChannelMonitor`]: channelmonitor::ChannelMonitor
154+
/// [`ChannelMonitor::block_connected`]: channelmonitor::ChannelMonitor::block_connected
155+
pub struct WatchedOutput {
156+
/// First block where the transaction output may have been spent.
157+
pub block_hash: Option<BlockHash>,
158+
159+
/// Outpoint identifying the transaction output.
160+
pub outpoint: OutPoint,
161+
162+
/// Spending condition of the transaction output.
163+
pub script_pubkey: Script,
138164
}
139165

140166
impl<T: Listen> Listen for std::ops::Deref<Target = T> {

lightning/src/util/test_utils.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// licenses.
99

1010
use chain;
11+
use chain::WatchedOutput;
1112
use chain::chaininterface;
1213
use chain::chaininterface::ConfirmationTarget;
1314
use chain::chainmonitor;
@@ -546,8 +547,8 @@ impl chain::Filter for TestChainSource {
546547
self.watched_txn.lock().unwrap().insert((*txid, script_pubkey.clone()));
547548
}
548549

549-
fn register_output(&self, outpoint: &OutPoint, script_pubkey: &Script) -> Option<(usize, Transaction)> {
550-
self.watched_outputs.lock().unwrap().insert((*outpoint, script_pubkey.clone()));
550+
fn register_output(&self, output: WatchedOutput) -> Option<(usize, Transaction)> {
551+
self.watched_outputs.lock().unwrap().insert((output.outpoint, output.script_pubkey));
551552
None
552553
}
553554
}

0 commit comments

Comments
 (0)