Skip to content

Commit ccb8039

Browse files
committed
f: store all counterparty revokeable spks in ChannelMonitor state
1 parent e3fb17f commit ccb8039

File tree

2 files changed

+57
-27
lines changed

2 files changed

+57
-27
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ pub(crate) enum ChannelMonitorUpdateStep {
543543
feerate_per_kw: Option<u32>,
544544
to_broadcaster_value_sat: Option<u64>,
545545
to_countersignatory_value_sat: Option<u64>,
546+
tolocal_spk: ScriptBuf,
546547
},
547548
PaymentPreimage {
548549
payment_preimage: PaymentPreimage,
@@ -594,6 +595,7 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
594595
(4, their_per_commitment_point, required),
595596
(5, to_countersignatory_value_sat, option),
596597
(6, htlc_outputs, required_vec),
598+
(8, tolocal_spk, required),
597599
},
598600
(2, PaymentPreimage) => {
599601
(0, payment_preimage, required),
@@ -893,6 +895,8 @@ pub(crate) struct ChannelMonitorImpl<Signer: ChannelSigner> {
893895
/// the payment hash from `HTLCOutputInCommitment` to claim even a revoked commitment
894896
/// transaction broadcast as we need to be able to construct the witness script in all cases.
895897
counterparty_claimable_outpoints: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
898+
/// `to_local` outpoints
899+
tolocal_claimable_outpoints: HashMap<Txid, ScriptBuf>,
896900
/// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain.
897901
/// Nor can we figure out their commitment numbers without the commitment transaction they are
898902
/// spending. Thus, in order to claim them via revocation key, we track all the counterparty
@@ -1133,6 +1137,11 @@ impl<Signer: ChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
11331137
htlc_source.as_ref().map(|b| b.as_ref()).write(writer)?;
11341138
}
11351139
}
1140+
writer.write_all(&(self.tolocal_claimable_outpoints.len() as u64).to_be_bytes())?;
1141+
for (ref txid, ref spk) in self.tolocal_claimable_outpoints.iter() {
1142+
writer.write_all(&txid[..])?;
1143+
spk.write(writer)?;
1144+
}
11361145

11371146
writer.write_all(&(self.counterparty_commitment_txn_on_chain.len() as u64).to_be_bytes())?;
11381147
for (ref txid, commitment_number) in self.counterparty_commitment_txn_on_chain.iter() {
@@ -1416,6 +1425,7 @@ impl<Signer: ChannelSigner> ChannelMonitor<Signer> {
14161425

14171426
commitment_secrets: CounterpartyCommitmentSecrets::new(),
14181427
counterparty_claimable_outpoints: new_hash_map(),
1428+
tolocal_claimable_outpoints: new_hash_map(),
14191429
counterparty_commitment_txn_on_chain: new_hash_map(),
14201430
counterparty_hash_commitment_number: new_hash_map(),
14211431
counterparty_fulfilled_htlcs: new_hash_map(),
@@ -1466,15 +1476,15 @@ impl<Signer: ChannelSigner> ChannelMonitor<Signer> {
14661476
pub(crate) fn provide_initial_counterparty_commitment_tx<L: Deref>(
14671477
&self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
14681478
commitment_number: u64, their_cur_per_commitment_point: PublicKey, feerate_per_kw: u32,
1469-
to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, logger: &L,
1479+
to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, logger: &L, tolocal_spk: ScriptBuf,
14701480
)
14711481
where L::Target: Logger
14721482
{
14731483
let mut inner = self.inner.lock().unwrap();
14741484
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
14751485
inner.provide_initial_counterparty_commitment_tx(txid,
14761486
htlc_outputs, commitment_number, their_cur_per_commitment_point, feerate_per_kw,
1477-
to_broadcaster_value_sat, to_countersignatory_value_sat, &logger);
1487+
to_broadcaster_value_sat, to_countersignatory_value_sat, &logger, tolocal_spk);
14781488
}
14791489

14801490
/// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction.
@@ -1489,11 +1499,12 @@ impl<Signer: ChannelSigner> ChannelMonitor<Signer> {
14891499
commitment_number: u64,
14901500
their_per_commitment_point: PublicKey,
14911501
logger: &L,
1502+
tolocal_spk: ScriptBuf,
14921503
) where L::Target: Logger {
14931504
let mut inner = self.inner.lock().unwrap();
14941505
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
14951506
inner.provide_latest_counterparty_commitment_tx(
1496-
txid, htlc_outputs, commitment_number, their_per_commitment_point, &logger)
1507+
txid, htlc_outputs, commitment_number, their_per_commitment_point, &logger, tolocal_spk)
14971508
}
14981509

14991510
#[cfg(test)]
@@ -2835,6 +2846,7 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
28352846
&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
28362847
commitment_number: u64, their_per_commitment_point: PublicKey, feerate_per_kw: u32,
28372848
to_broadcaster_value: u64, to_countersignatory_value: u64, logger: &WithChannelMonitor<L>,
2849+
tolocal_spk: ScriptBuf,
28382850
) where L::Target: Logger {
28392851
self.initial_counterparty_commitment_info = Some((their_per_commitment_point.clone(),
28402852
feerate_per_kw, to_broadcaster_value, to_countersignatory_value));
@@ -2845,13 +2857,14 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
28452857
}
28462858

28472859
self.provide_latest_counterparty_commitment_tx(txid, htlc_outputs, commitment_number,
2848-
their_per_commitment_point, logger);
2860+
their_per_commitment_point, logger, tolocal_spk);
28492861
}
28502862

28512863
fn provide_latest_counterparty_commitment_tx<L: Deref>(
28522864
&mut self, txid: Txid,
28532865
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
28542866
commitment_number: u64, their_per_commitment_point: PublicKey, logger: &WithChannelMonitor<L>,
2867+
tolocal_claimable_spk: ScriptBuf,
28552868
) where L::Target: Logger {
28562869
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
28572870
// so that a remote monitor doesn't learn anything unless there is a malicious close.
@@ -2865,6 +2878,7 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
28652878
self.prev_counterparty_commitment_txid = self.current_counterparty_commitment_txid.take();
28662879
self.current_counterparty_commitment_txid = Some(txid);
28672880
self.counterparty_claimable_outpoints.insert(txid, htlc_outputs.clone());
2881+
self.tolocal_claimable_outpoints.insert(txid, tolocal_claimable_spk);
28682882
self.current_counterparty_commitment_number = commitment_number;
28692883
//TODO: Merge this into the other per-counterparty-transaction output storage stuff
28702884
match self.their_cur_per_commitment_points {
@@ -3199,9 +3213,9 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
31993213
ret = Err(());
32003214
}
32013215
}
3202-
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, .. } => {
3216+
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, tolocal_spk, .. } => {
32033217
log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info");
3204-
self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_per_commitment_point, logger)
3218+
self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_per_commitment_point, logger, tolocal_spk.clone())
32053219
},
32063220
ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage, payment_info } => {
32073221
log_trace!(logger, "Updating ChannelMonitor with payment preimage");
@@ -3427,11 +3441,12 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
34273441
fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
34283442
update.updates.iter().filter_map(|update| {
34293443
match update {
3444+
// TODO: must fix this ignore here - can you build the full commitment transaction back from just the update?
34303445
&ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid,
34313446
ref htlc_outputs, commitment_number, their_per_commitment_point,
34323447
feerate_per_kw: Some(feerate_per_kw),
34333448
to_broadcaster_value_sat: Some(to_broadcaster_value),
3434-
to_countersignatory_value_sat: Some(to_countersignatory_value) } => {
3449+
to_countersignatory_value_sat: Some(to_countersignatory_value), ref tolocal_spk } => {
34353450

34363451
let nondust_htlcs = htlc_outputs.iter().filter_map(|(htlc, _)| {
34373452
htlc.transaction_output_index.map(|_| (htlc.clone(), None))
@@ -3441,6 +3456,7 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
34413456
&their_per_commitment_point, to_broadcaster_value,
34423457
to_countersignatory_value, feerate_per_kw, nondust_htlcs);
34433458

3459+
debug_assert_eq!(&commitment_tx.trust().revokeable_spk(), tolocal_spk);
34443460
debug_assert_eq!(commitment_tx.trust().txid(), commitment_txid);
34453461

34463462
Some(commitment_tx)
@@ -3510,21 +3526,22 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
35103526
let secret = self.get_secret(commitment_number).unwrap();
35113527
let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret));
35123528
let per_commitment_point = PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key);
3513-
let revokeable_spk = self.onchain_tx_handler.signer.get_revokeable_spk(false, commitment_number, &per_commitment_point, &self.onchain_tx_handler.secp_ctx);
35143529
let punishment_witness_weight = self.onchain_tx_handler.signer.get_punishment_witness_weight();
35153530

35163531
// First, process non-htlc outputs (to_holder & to_counterparty)
3517-
for (idx, outp) in tx.output.iter().enumerate() {
3518-
if outp.script_pubkey == revokeable_spk {
3519-
let revk_outp = RevokedOutput::build(per_commitment_point, per_commitment_key, outp.value, self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx(), punishment_witness_weight);
3520-
let justice_package = PackageTemplate::build_package(
3521-
commitment_txid, idx as u32,
3522-
PackageSolvingData::RevokedOutput(revk_outp),
3523-
height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32,
3524-
);
3525-
claimable_outpoints.push(justice_package);
3526-
to_counterparty_output_info =
3527-
Some((idx.try_into().expect("Txn can't have more than 2^32 outputs"), outp.value));
3532+
if let Some(rev_spk) = self.tolocal_claimable_outpoints.get(&commitment_txid) {
3533+
for (idx, outp) in tx.output.iter().enumerate() {
3534+
if &outp.script_pubkey == rev_spk {
3535+
let revk_outp = RevokedOutput::build(per_commitment_point, per_commitment_key, outp.value, self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx(), punishment_witness_weight);
3536+
let justice_package = PackageTemplate::build_package(
3537+
commitment_txid, idx as u32,
3538+
PackageSolvingData::RevokedOutput(revk_outp),
3539+
height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32,
3540+
);
3541+
claimable_outpoints.push(justice_package);
3542+
to_counterparty_output_info =
3543+
Some((idx.try_into().expect("Txn can't have more than 2^32 outputs"), outp.value));
3544+
}
35283545
}
35293546
}
35303547

@@ -3626,9 +3643,10 @@ impl<Signer: ChannelSigner> ChannelMonitorImpl<Signer> {
36263643
} else { return (claimable_outpoints, to_counterparty_output_info); };
36273644

36283645
if let Some(transaction) = tx {
3629-
let revokeable_spk = self.onchain_tx_handler.signer.get_revokeable_spk(false, commitment_number, &per_commitment_point, &self.onchain_tx_handler.secp_ctx);
3646+
// unwrap because we are sure to be looking at a counterparty commitment transaction
3647+
let revokeable_spk = self.tolocal_claimable_outpoints.get(&commitment_txid).unwrap();
36303648
for (idx, outp) in transaction.output.iter().enumerate() {
3631-
if outp.script_pubkey == revokeable_spk {
3649+
if &outp.script_pubkey == revokeable_spk {
36323650
to_counterparty_output_info =
36333651
Some((idx.try_into().expect("Can't have > 2^32 outputs"), outp.value));
36343652
}
@@ -4815,6 +4833,15 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
48154833
return Err(DecodeError::InvalidValue);
48164834
}
48174835
}
4836+
let tolocal_claimable_outpoints_len: u64 = Readable::read(reader)?;
4837+
let mut tolocal_claimable_outpoints = hash_map_with_capacity(cmp::min(tolocal_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64));
4838+
for _ in 0..tolocal_claimable_outpoints_len {
4839+
let txid: Txid = Readable::read(reader)?;
4840+
let spk: ScriptBuf = Readable::read(reader)?;
4841+
if tolocal_claimable_outpoints.insert(txid, spk).is_some() {
4842+
return Err(DecodeError::InvalidValue);
4843+
}
4844+
}
48184845

48194846
let counterparty_commitment_txn_on_chain_len: u64 = Readable::read(reader)?;
48204847
let mut counterparty_commitment_txn_on_chain = hash_map_with_capacity(cmp::min(counterparty_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32));
@@ -5014,6 +5041,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
50145041

50155042
commitment_secrets,
50165043
counterparty_claimable_outpoints,
5044+
tolocal_claimable_outpoints,
50175045
counterparty_commitment_txn_on_chain,
50185046
counterparty_hash_commitment_number,
50195047
counterparty_fulfilled_htlcs: counterparty_fulfilled_htlcs.unwrap(),
@@ -5289,9 +5317,9 @@ mod tests {
52895317
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
52905318
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap();
52915319
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"1").to_byte_array()),
5292-
preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger);
5320+
preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger, dummy_commitment_tx.trust().revokeable_spk());
52935321
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"2").to_byte_array()),
5294-
preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key, &logger);
5322+
preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key, &logger, dummy_commitment_tx.trust().revokeable_spk());
52955323
for &(ref preimage, ref hash) in preimages.iter() {
52965324
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
52975325
monitor.provide_payment_preimage_unsafe_legacy(
@@ -5308,7 +5336,7 @@ mod tests {
53085336
test_preimages_exist!(&preimages[15..20], monitor);
53095337

53105338
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"3").to_byte_array()),
5311-
preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key, &logger);
5339+
preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key, &logger, dummy_commitment_tx.trust().revokeable_spk());
53125340

53135341
// Now provide a further secret, pruning preimages 15-17
53145342
secret[0..32].clone_from_slice(&<Vec<u8>>::from_hex("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
@@ -5318,7 +5346,7 @@ mod tests {
53185346
test_preimages_exist!(&preimages[17..20], monitor);
53195347

53205348
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"4").to_byte_array()),
5321-
preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key, &logger);
5349+
preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key, &logger, dummy_commitment_tx.trust().revokeable_spk());
53225350

53235351
// Now update holder commitment tx info, pruning only element 18 as we still care about the
53245352
// previous commitment tx's preimages too

lightning/src/ln/channel.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ trait InitialRemoteCommitmentReceiver<SP: Deref> where SP::Target: SignerProvide
18001800
let counterparty_initial_commitment_tx = context.build_commitment_transaction(context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
18011801
let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
18021802
let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
1803+
let counterparty_tolocal_spk = counterparty_trusted_tx.revokeable_spk();
18031804

18041805
log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
18051806
&context.channel_id(), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
@@ -1843,7 +1844,7 @@ trait InitialRemoteCommitmentReceiver<SP: Deref> where SP::Target: SignerProvide
18431844
counterparty_initial_commitment_tx.feerate_per_kw(),
18441845
counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
18451846
counterparty_initial_commitment_tx.to_countersignatory_value_sat(),
1846-
logger);
1847+
logger, counterparty_tolocal_spk);
18471848

18481849
context.cur_counterparty_commitment_transaction_number -= 1;
18491850

@@ -5235,7 +5236,7 @@ impl<SP: Deref> FundedChannel<SP> where
52355236
self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, commitment_stats.outbound_htlc_preimages, &self.context.secp_ctx)
52365237
.map_err(|_| ChannelError::close("Failed to validate our commitment".to_owned()))?;
52375238

5238-
let mut htlcs_cloned: Vec<_> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
5239+
let mut htlcs_cloned: Vec<(HTLCOutputInCommitment, Option<HTLCSource>)> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
52395240

52405241
// If our counterparty updated the channel fee in this commitment transaction, check that
52415242
// they can actually afford the new fee now.
@@ -8148,6 +8149,7 @@ impl<SP: Deref> FundedChannel<SP> where
81488149
feerate_per_kw: Some(counterparty_commitment_tx.feerate_per_kw()),
81498150
to_broadcaster_value_sat: Some(counterparty_commitment_tx.to_broadcaster_value_sat()),
81508151
to_countersignatory_value_sat: Some(counterparty_commitment_tx.to_countersignatory_value_sat()),
8152+
tolocal_spk: counterparty_commitment_tx.trust().revokeable_spk(),
81518153
}],
81528154
channel_id: Some(self.context.channel_id()),
81538155
};

0 commit comments

Comments
 (0)