Skip to content

Commit 7bf4380

Browse files
author
Antoine Riard
committed
Add transaction index in watch_outputs
Previously, outputs were monitored based on txid and an index yelled from an enumeration over the returned selected outputs by monitoring code. This is broken we don't have a guarantee that HTLC outputs are ranking first after introduction of anchor outputs.
1 parent 09e7ca8 commit 7bf4380

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

lightning/src/ln/channelmonitor.rs

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ impl<Key : Send + cmp::Eq + hash::Hash, ChanSigner: ChannelKeys, T: Deref + Sync
222222
let txn_outputs = monitor.block_connected(txn_matched, height, &block_hash, &*self.broadcaster, &*self.fee_estimator, &*self.logger, &*self.utxo_pool);
223223

224224
for (ref txid, ref outputs) in txn_outputs {
225-
for (idx, output) in outputs.iter().enumerate() {
226-
self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey);
225+
for (idx, script) in outputs.iter() {
226+
self.chain_monitor.install_watch_outpoint((txid.clone(), *idx), &script.script_pubkey);
227227
}
228228
}
229229
}
@@ -274,8 +274,8 @@ impl<Key : Send + cmp::Eq + hash::Hash + 'static, ChanSigner: ChannelKeys, T: De
274274
self.chain_monitor.install_watch_tx(&funding_txo.0.txid, &funding_txo.1);
275275
self.chain_monitor.install_watch_outpoint((funding_txo.0.txid, funding_txo.0.index as u32), &funding_txo.1);
276276
for (txid, outputs) in monitor.get_outputs_to_watch().iter() {
277-
for (idx, script) in outputs.iter().enumerate() {
278-
self.chain_monitor.install_watch_outpoint((*txid, idx as u32), script);
277+
for (idx, script) in outputs.iter() {
278+
self.chain_monitor.install_watch_outpoint((txid.clone(), *idx), &script);
279279
}
280280
}
281281
}
@@ -679,7 +679,7 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
679679
// interface knows about the TXOs that we want to be notified of spends of. We could probably
680680
// be smart and derive them from the above storage fields, but its much simpler and more
681681
// Obviously Correct (tm) if we just keep track of them explicitly.
682-
outputs_to_watch: HashMap<Txid, Vec<Script>>,
682+
outputs_to_watch: HashMap<Txid, Vec<(u32, Script)>>,
683683

684684
#[cfg(test)]
685685
pub onchain_tx_handler: OnchainTxHandler<ChanSigner>,
@@ -1000,10 +1000,11 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
10001000
}
10011001

10021002
(self.outputs_to_watch.len() as u64).write(writer)?;
1003-
for (txid, output_scripts) in self.outputs_to_watch.iter() {
1003+
for (txid, idx_scripts) in self.outputs_to_watch.iter() {
10041004
txid.write(writer)?;
1005-
(output_scripts.len() as u64).write(writer)?;
1006-
for script in output_scripts.iter() {
1005+
(idx_scripts.len() as u64).write(writer)?;
1006+
for (idx, script) in idx_scripts.iter() {
1007+
idx.write(writer)?;
10071008
script.write(writer)?;
10081009
}
10091010
}
@@ -1292,7 +1293,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
12921293
/// transaction), which we must learn about spends of via block_connected().
12931294
///
12941295
/// (C-not exported) because we have no HashMap bindings
1295-
pub fn get_outputs_to_watch(&self) -> &HashMap<Txid, Vec<Script>> {
1296+
pub fn get_outputs_to_watch(&self) -> &HashMap<Txid, Vec<(u32, Script)>> {
12961297
&self.outputs_to_watch
12971298
}
12981299

@@ -1305,7 +1306,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13051306
pub fn get_monitored_outpoints(&self) -> Vec<(Txid, u32, &Script)> {
13061307
let mut res = Vec::with_capacity(self.counterparty_commitment_txn_on_chain.len() * 2);
13071308
for (ref txid, &(_, ref outputs)) in self.counterparty_commitment_txn_on_chain.iter() {
1308-
for (idx, output) in outputs.iter().enumerate() {
1309+
for (idx, output) in outputs.iter().enumerate() {
13091310
res.push(((*txid).clone(), idx as u32, output));
13101311
}
13111312
}
@@ -1354,8 +1355,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13541355
/// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
13551356
/// HTLC-Success/HTLC-Timeout transactions.
13561357
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
1357-
/// revoked counterparty commitment tx
1358-
fn check_spend_counterparty_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<OnchainRequest>, (Txid, Vec<TxOut>)) where L::Target: Logger {
1358+
/// revoked remote commitment tx
1359+
fn check_spend_counterparty_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<OnchainRequest>, (Txid, Vec<(u32, TxOut)>)) where L::Target: Logger {
13591360
// Most secp and related errors trying to create keys means we have no hope of constructing
13601361
// a spend transaction...so we return no transactions to broadcast
13611362
let mut claimable_outpoints = Vec::new();
@@ -1410,7 +1411,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14101411
if !claimable_outpoints.is_empty() || per_commitment_option.is_some() { // ie we're confident this is actually ours
14111412
// We're definitely a counterparty commitment transaction!
14121413
log_trace!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len());
1413-
watch_outputs.append(&mut tx.output.clone());
1414+
for (idx, outp) in tx.output.iter().enumerate() {
1415+
watch_outputs.push((idx as u32, outp.clone()));
1416+
}
14141417
self.counterparty_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
14151418

14161419
macro_rules! check_htlc_fails {
@@ -1457,7 +1460,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14571460
// already processed the block, resulting in the counterparty_commitment_txn_on_chain entry
14581461
// not being generated by the above conditional. Thus, to be safe, we go ahead and
14591462
// insert it here.
1460-
watch_outputs.append(&mut tx.output.clone());
1463+
for (idx, outp) in tx.output.iter().enumerate() {
1464+
watch_outputs.push((idx as u32, outp.clone()));
1465+
}
14611466
self.counterparty_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
14621467

14631468
log_trace!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid);
@@ -1546,7 +1551,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15461551
}
15471552

15481553
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
1549-
fn check_spend_counterparty_htlc<L: Deref>(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec<OnchainRequest>, Option<(Txid, Vec<TxOut>)>) where L::Target: Logger {
1554+
fn check_spend_counterparty_htlc<L: Deref>(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec<OnchainRequest>, Option<(Txid, Vec<(u32, TxOut)>)>) where L::Target: Logger {
15501555
let htlc_txid = tx.txid();
15511556
if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 {
15521557
return (Vec::new(), None)
@@ -1568,10 +1573,11 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15681573
log_trace!(logger, "Remote HTLC broadcast {}:{}", htlc_txid, 0);
15691574
let malleable_justice_tx = PackageTemplate::build_malleable_justice_tx(per_commitment_point, per_commitment_key, self.counterparty_tx_cache.counterparty_delayed_payment_base_key, self.counterparty_tx_cache.counterparty_htlc_base_key, InputDescriptors::RevokedOutput, htlc_txid, 0, tx.output[0].value, None, self.counterparty_tx_cache.on_counterparty_tx_csv);
15701575
let claimable_outpoints = vec!(OnchainRequest { aggregation: true, bump_strategy: BumpStrategy::RBF, feerate_previous: 0, height_timer: None, absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, height_original: height, content: malleable_justice_tx });
1571-
(claimable_outpoints, Some((htlc_txid, tx.output.clone())))
1576+
let outputs = vec![(0, tx.output[0].clone())];
1577+
(claimable_outpoints, Some((htlc_txid, outputs)))
15721578
}
15731579

1574-
fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx, height: u32) -> (Vec<OnchainRequest>, Vec<TxOut>, Option<(Script, PublicKey, PublicKey)>) {
1580+
fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx, height: u32) -> (Vec<OnchainRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
15751581
let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len());
15761582
let mut watch_outputs = Vec::with_capacity(holder_tx.htlc_outputs.len());
15771583

@@ -1589,7 +1595,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15891595
}
15901596
} else { None }, htlc.amount_msat, holder_tx.txid, transaction_output_index);
15911597
claim_requests.push(OnchainRequest { aggregation: false, bump_strategy: BumpStrategy::CPFP, feerate_previous: 0, height_timer: None, absolute_timelock: height, height_original: height, content: holder_htlc_tx });
1592-
watch_outputs.push(commitment_tx.output[transaction_output_index as usize].clone());
1598+
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
15931599
}
15941600
}
15951601

@@ -1599,7 +1605,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15991605
/// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
16001606
/// revoked using data in holder_claimable_outpoints.
16011607
/// Should not be used if check_spend_revoked_transaction succeeds.
1602-
fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<OnchainRequest>, (Txid, Vec<TxOut>)) where L::Target: Logger {
1608+
fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<OnchainRequest>, (Txid, Vec<(u32, TxOut)>)) where L::Target: Logger {
16031609
let commitment_txid = tx.txid();
16041610
let mut claim_requests = Vec::new();
16051611
let mut watch_outputs = Vec::new();
@@ -1743,7 +1749,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17431749
/// Eventually this should be pub and, roughly, implement ChainListener, however this requires
17441750
/// &mut self, as well as returns new spendable outputs and outpoints to watch for spending of
17451751
/// on-chain.
1746-
fn block_connected<B: Deref, F: Deref, L: Deref, U: Deref>(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F, logger: L, utxo_pool: U)-> Vec<(Txid, Vec<TxOut>)>
1752+
fn block_connected<B: Deref, F: Deref, L: Deref, U: Deref>(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F, logger: L, utxo_pool: U)-> Vec<(Txid, Vec<(u32, TxOut)>)>
17471753
where B::Target: BroadcasterInterface,
17481754
F::Target: FeeEstimator,
17491755
L::Target: Logger,
@@ -1839,8 +1845,8 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18391845
self.onchain_tx_handler.block_connected(txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger, &*utxo_pool);
18401846

18411847
self.last_block_hash = block_hash.clone();
1842-
for &(ref txid, ref output_scripts) in watch_outputs.iter() {
1843-
self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect());
1848+
for &(ref txid, ref idx_scripts) in watch_outputs.iter() {
1849+
self.outputs_to_watch.insert(txid.clone(), idx_scripts.iter().map(|o| (o.0, o.1.script_pubkey.clone())).collect());
18441850
}
18451851

18461852
watch_outputs
@@ -2361,13 +2367,13 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor
23612367
}
23622368

23632369
let outputs_to_watch_len: u64 = Readable::read(reader)?;
2364-
let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<Txid>() + mem::size_of::<Vec<Script>>())));
2370+
let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<Txid>() + mem::size_of::<u32>() + mem::size_of::<Vec<Script>>())));
23652371
for _ in 0..outputs_to_watch_len {
23662372
let txid = Readable::read(reader)?;
23672373
let outputs_len: u64 = Readable::read(reader)?;
2368-
let mut outputs = Vec::with_capacity(cmp::min(outputs_len as usize, MAX_ALLOC_SIZE / mem::size_of::<Script>()));
2374+
let mut outputs = Vec::with_capacity(cmp::min(outputs_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<u32>() + mem::size_of::<Script>())));
23692375
for _ in 0..outputs_len {
2370-
outputs.push(Readable::read(reader)?);
2376+
outputs.push((Readable::read(reader)?, Readable::read(reader)?));
23712377
}
23722378
if let Some(_) = outputs_to_watch.insert(txid, outputs) {
23732379
return Err(DecodeError::InvalidValue);

0 commit comments

Comments
 (0)