Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove exclusive reference and generic from CommitmentTransaction API #3689

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 47 additions & 41 deletions lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
@@ -317,7 +317,7 @@ impl HolderCommitment {
let delayed_payment_key = &tx_keys.broadcaster_delayed_payment_key;
let per_commitment_point = &tx_keys.per_commitment_point;

let mut nondust_htlcs = self.tx.htlcs().iter().zip(self.tx.counterparty_htlc_sigs.iter());
let mut nondust_htlcs = self.tx.nondust_htlcs().iter().zip(self.tx.counterparty_htlc_sigs.iter());
let mut sources = self.nondust_htlc_sources.iter();

// Use an iterator to write `htlc_outputs` to avoid allocations.
@@ -937,7 +937,7 @@ impl TryFrom<(HolderCommitmentTransaction, HolderSignedTx)> for HolderCommitment
// HTLC sources, separately. All offered, non-dust HTLCs must have a source available.

let mut missing_nondust_source = false;
let mut nondust_htlc_sources = Vec::with_capacity(holder_commitment_tx.htlcs().len());
let mut nondust_htlc_sources = Vec::with_capacity(holder_commitment_tx.nondust_htlcs().len());
let dust_htlcs = holder_signed_tx.htlc_outputs.into_iter().filter_map(|(htlc, _, source)| {
// Filter our non-dust HTLCs, while at the same time pushing their sources into
// `nondust_htlc_sources`.
@@ -967,16 +967,16 @@ impl TryFrom<(HolderCommitmentTransaction, HolderSignedTx)> for HolderCommitment

impl HolderCommitment {
fn has_htlcs(&self) -> bool {
self.tx.htlcs().len() > 0 || self.dust_htlcs.len() > 0
self.tx.nondust_htlcs().len() > 0 || self.dust_htlcs.len() > 0
}

fn htlcs(&self) -> impl Iterator<Item = &HTLCOutputInCommitment> {
self.tx.htlcs().iter().chain(self.dust_htlcs.iter().map(|(htlc, _)| htlc))
self.tx.nondust_htlcs().iter().chain(self.dust_htlcs.iter().map(|(htlc, _)| htlc))
}

fn htlcs_with_sources(&self) -> impl Iterator<Item = (&HTLCOutputInCommitment, Option<&HTLCSource>)> {
let mut sources = self.nondust_htlc_sources.iter();
let nondust_htlcs = self.tx.htlcs().iter().map(move |htlc| {
let nondust_htlcs = self.tx.nondust_htlcs().iter().map(move |htlc| {
let mut source = None;
if htlc.offered && htlc.transaction_output_index.is_some() {
source = sources.next();
@@ -3093,8 +3093,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
// If we have non-dust HTLCs in htlc_outputs, ensure they match the HTLCs in the
// `holder_commitment_tx`. In the future, we'll no longer provide the redundant data
// and just pass in source data via `nondust_htlc_sources`.
debug_assert_eq!(htlc_outputs.iter().filter(|(_, s, _)| s.is_some()).count(), holder_commitment_tx.trust().htlcs().len());
for (a, b) in htlc_outputs.iter().filter(|(_, s, _)| s.is_some()).map(|(h, _, _)| h).zip(holder_commitment_tx.trust().htlcs().iter()) {
debug_assert_eq!(htlc_outputs.iter().filter(|(_, s, _)| s.is_some()).count(), holder_commitment_tx.trust().nondust_htlcs().len());
for (a, b) in htlc_outputs.iter().filter(|(_, s, _)| s.is_some()).map(|(h, _, _)| h).zip(holder_commitment_tx.trust().nondust_htlcs().iter()) {
debug_assert_eq!(a, b);
}
debug_assert_eq!(htlc_outputs.iter().filter(|(_, s, _)| s.is_some()).count(), holder_commitment_tx.counterparty_htlc_sigs.len());
@@ -3104,7 +3104,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {

// Backfill the non-dust HTLC sources.
debug_assert!(nondust_htlc_sources.is_empty());
nondust_htlc_sources.reserve_exact(holder_commitment_tx.htlcs().len());
nondust_htlc_sources.reserve_exact(holder_commitment_tx.nondust_htlcs().len());
let dust_htlcs = htlc_outputs.into_iter().filter_map(|(htlc, _, source)| {
// Filter our non-dust HTLCs, while at the same time pushing their sources into
// `nondust_htlc_sources`.
@@ -3124,18 +3124,18 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
// `nondust_htlc_sources` and the `holder_commitment_tx`
{
let mut prev = -1;
for htlc in holder_commitment_tx.trust().htlcs().iter() {
for htlc in holder_commitment_tx.trust().nondust_htlcs().iter() {
assert!(htlc.transaction_output_index.unwrap() as i32 > prev);
prev = htlc.transaction_output_index.unwrap() as i32;
}
}

debug_assert!(htlc_outputs.iter().all(|(htlc, _, _)| htlc.transaction_output_index.is_none()));
debug_assert!(htlc_outputs.iter().all(|(_, sig_opt, _)| sig_opt.is_none()));
debug_assert_eq!(holder_commitment_tx.trust().htlcs().len(), holder_commitment_tx.counterparty_htlc_sigs.len());
debug_assert_eq!(holder_commitment_tx.trust().nondust_htlcs().len(), holder_commitment_tx.counterparty_htlc_sigs.len());

let mut sources = nondust_htlc_sources.iter();
for htlc in holder_commitment_tx.trust().htlcs().iter() {
for htlc in holder_commitment_tx.trust().nondust_htlcs().iter() {
if htlc.offered {
let source = sources.next().expect("Non-dust HTLC sources didn't match commitment tx");
assert!(source.possibly_matches_output(htlc));
@@ -3526,7 +3526,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
let counterparty_node_id = self.counterparty_node_id;
let commitment_txid = commitment_tx.compute_txid();
debug_assert_eq!(self.funding.current_holder_commitment.tx.trust().txid(), commitment_txid);
let pending_htlcs = self.funding.current_holder_commitment.tx.trust().htlcs().to_vec();
let pending_htlcs = self.funding.current_holder_commitment.tx.trust().nondust_htlcs().to_vec();
let channel_value_satoshis = self.funding.channel_parameters.channel_value_satoshis;
let commitment_tx_fee_satoshis = channel_value_satoshis -
commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value.to_sat());
@@ -3598,15 +3598,15 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
to_broadcaster_value,
to_countersignatory_value,
)| {
let htlc_outputs = vec![];
let nondust_htlcs = vec![];

let commitment_tx = self.build_counterparty_commitment_tx(
INITIAL_COMMITMENT_NUMBER,
&their_per_commitment_point,
to_broadcaster_value,
to_countersignatory_value,
feerate_per_kw,
htlc_outputs,
&nondust_htlcs,
);
// Take the opportunity to populate this recently introduced field
self.initial_counterparty_commitment_tx = Some(commitment_tx.clone());
@@ -3619,11 +3619,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
fn build_counterparty_commitment_tx(
&self, commitment_number: u64, their_per_commitment_point: &PublicKey,
to_broadcaster_value: u64, to_countersignatory_value: u64, feerate_per_kw: u32,
mut nondust_htlcs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>
nondust_htlcs: &Vec<HTLCOutputInCommitment>
) -> CommitmentTransaction {
let channel_parameters = &self.funding.channel_parameters.as_counterparty_broadcastable();
CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, their_per_commitment_point,
to_broadcaster_value, to_countersignatory_value, feerate_per_kw, &mut nondust_htlcs, channel_parameters, &self.onchain_tx_handler.secp_ctx)
CommitmentTransaction::new(commitment_number, their_per_commitment_point,
to_broadcaster_value, to_countersignatory_value, feerate_per_kw, nondust_htlcs, channel_parameters, &self.onchain_tx_handler.secp_ctx)
}

fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
@@ -3639,12 +3639,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
to_countersignatory_value_sat: Some(to_countersignatory_value) } => {

let nondust_htlcs = htlc_outputs.iter().filter_map(|(htlc, _)| {
htlc.transaction_output_index.map(|_| (htlc.clone(), None))
htlc.transaction_output_index.map(|_| htlc).cloned()
}).collect::<Vec<_>>();

let commitment_tx = self.build_counterparty_commitment_tx(commitment_number,
&their_per_commitment_point, to_broadcaster_value,
to_countersignatory_value, feerate_per_kw, nondust_htlcs);
to_countersignatory_value, feerate_per_kw, &nondust_htlcs);

debug_assert_eq!(commitment_tx.trust().txid(), commitment_txid);

@@ -3973,7 +3973,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
fn get_broadcasted_holder_claims(
&self, holder_tx: &HolderCommitmentTransaction, conf_height: u32,
) -> (Vec<PackageTemplate>, Option<(ScriptBuf, PublicKey, RevocationKey)>) {
let mut claim_requests = Vec::with_capacity(holder_tx.htlcs().len());
let mut claim_requests = Vec::with_capacity(holder_tx.nondust_htlcs().len());

let tx = holder_tx.trust();
let keys = tx.keys();
@@ -3985,7 +3985,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
));

let txid = tx.txid();
for htlc in holder_tx.htlcs() {
for htlc in holder_tx.nondust_htlcs() {
if let Some(transaction_output_index) = htlc.transaction_output_index {
let (htlc_output, counterparty_spendable_height) = if htlc.offered {
let htlc_output = HolderHTLCOutput::build_offered(
@@ -4020,9 +4020,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {

// Returns holder HTLC outputs to watch and react to in case of spending.
fn get_broadcasted_holder_watch_outputs(&self, holder_tx: &HolderCommitmentTransaction) -> Vec<(u32, TxOut)> {
let mut watch_outputs = Vec::with_capacity(holder_tx.htlcs().len());
let mut watch_outputs = Vec::with_capacity(holder_tx.nondust_htlcs().len());
let tx = holder_tx.trust();
for htlc in holder_tx.htlcs() {
for htlc in holder_tx.nondust_htlcs() {
if let Some(transaction_output_index) = htlc.transaction_output_index {
watch_outputs.push((
transaction_output_index,
@@ -4115,7 +4115,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
let txid = self.funding.current_holder_commitment.tx.trust().txid();
log_trace!(logger, "Canceling claims for previously broadcast holder commitment {}", txid);
let mut outpoint = BitcoinOutPoint { txid, vout: 0 };
for htlc in self.funding.current_holder_commitment.tx.htlcs() {
for htlc in self.funding.current_holder_commitment.tx.nondust_htlcs() {
if let Some(vout) = htlc.transaction_output_index {
outpoint.vout = vout;
self.onchain_tx_handler.abandon_claim(&outpoint);
@@ -4129,7 +4129,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
if txid != *confirmed_commitment_txid {
log_trace!(logger, "Canceling claims for previously broadcast holder commitment {}", txid);
let mut outpoint = BitcoinOutPoint { txid, vout: 0 };
for htlc in prev_holder_commitment.tx.htlcs() {
for htlc in prev_holder_commitment.tx.nondust_htlcs() {
if let Some(vout) = htlc.transaction_output_index {
outpoint.vout = vout;
self.onchain_tx_handler.abandon_claim(&outpoint);
@@ -4155,7 +4155,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
return holder_transactions;
}
for htlc in self.funding.current_holder_commitment.tx.htlcs() {
for htlc in self.funding.current_holder_commitment.tx.nondust_htlcs() {
if let Some(vout) = htlc.transaction_output_index {
let preimage = if !htlc.offered {
if let Some((preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) { Some(preimage.clone()) } else {
@@ -5595,21 +5595,21 @@ mod tests {
{
let mut res = Vec::new();
for (idx, preimage) in $preimages_slice.iter().enumerate() {
res.push((HTLCOutputInCommitment {
res.push(HTLCOutputInCommitment {
offered: true,
amount_msat: 0,
cltv_expiry: 0,
payment_hash: preimage.1.clone(),
transaction_output_index: Some(idx as u32),
}, ()));
});
}
res
}
}
}
macro_rules! preimages_slice_to_htlc_outputs {
($preimages_slice: expr) => {
preimages_slice_to_htlcs!($preimages_slice).into_iter().map(|(htlc, _)| (htlc, None)).collect()
preimages_slice_to_htlcs!($preimages_slice).into_iter().map(|htlc| (htlc, None)).collect()
}
}
let dummy_sig = crate::crypto::utils::sign(&secp_ctx,
@@ -5665,15 +5665,17 @@ mod tests {
let best_block = BestBlock::from_network(Network::Testnet);
let monitor = ChannelMonitor::new(
Secp256k1::new(), keys, Some(shutdown_script.into_inner()), 0, &ScriptBuf::new(),
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, &mut Vec::new()),
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, &Vec::new()),
best_block, dummy_key, channel_id,
);

let mut htlcs = preimages_slice_to_htlcs!(preimages[0..10]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs);
let nondust_htlcs = preimages_slice_to_htlcs!(preimages[0..10]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &nondust_htlcs);
// These htlcs now have their output indices assigned
let nondust_htlcs = dummy_commitment_tx.nondust_htlcs();

monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), Some(dummy_source.clone()))).collect());
nondust_htlcs.into_iter().map(|htlc| (htlc.clone(), Some(dummy_sig), Some(dummy_source.clone()))).collect());
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"1").to_byte_array()),
preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger);
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"2").to_byte_array()),
@@ -5708,21 +5710,25 @@ mod tests {

// Now update holder commitment tx info, pruning only element 18 as we still care about the
// previous commitment tx's preimages too
let mut htlcs = preimages_slice_to_htlcs!(preimages[0..5]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs);
let nondust_htlcs = preimages_slice_to_htlcs!(preimages[0..5]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &nondust_htlcs);
// These htlcs now have their output indices assigned
let nondust_htlcs = dummy_commitment_tx.nondust_htlcs();
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), Some(dummy_source.clone()))).collect());
nondust_htlcs.into_iter().map(|htlc| (htlc.clone(), Some(dummy_sig), Some(dummy_source.clone()))).collect());
secret[0..32].clone_from_slice(&<Vec<u8>>::from_hex("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secret.clone()).unwrap();
assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 12);
test_preimages_exist!(&preimages[0..10], monitor);
test_preimages_exist!(&preimages[18..20], monitor);

// But if we do it again, we'll prune 5-10
let mut htlcs = preimages_slice_to_htlcs!(preimages[0..3]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs);
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx,
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), Some(dummy_source.clone()))).collect());
let nondust_htlcs = preimages_slice_to_htlcs!(preimages[0..3]);
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &nondust_htlcs);
// These htlcs now have their output indices assigned
let nondust_htlcs = dummy_commitment_tx.nondust_htlcs();
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
nondust_htlcs.into_iter().map(|htlc| (htlc.clone(), Some(dummy_sig), Some(dummy_source.clone()))).collect());
secret[0..32].clone_from_slice(&<Vec<u8>>::from_hex("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secret.clone()).unwrap();
assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 5);
@@ -5917,7 +5923,7 @@ mod tests {
let best_block = BestBlock::from_network(Network::Testnet);
let monitor = ChannelMonitor::new(
Secp256k1::new(), keys, Some(shutdown_script.into_inner()), 0, &ScriptBuf::new(),
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, &mut Vec::new()),
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, &Vec::new()),
best_block, dummy_key, channel_id,
);

19 changes: 9 additions & 10 deletions lightning/src/chain/onchaintx.rs
Original file line number Diff line number Diff line change
@@ -1205,7 +1205,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
if trusted_tx.txid() != outp.txid {
return None;
}
let (htlc_idx, htlc) = trusted_tx.htlcs().iter().enumerate()
let (htlc_idx, htlc) = trusted_tx.nondust_htlcs().iter().enumerate()
.find(|(_, htlc)| htlc.transaction_output_index.unwrap() == outp.vout)
.unwrap();
let counterparty_htlc_sig = holder_commitment.counterparty_htlc_sigs[htlc_idx];
@@ -1248,7 +1248,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
if outp.txid != trusted_tx.txid() {
return None;
}
trusted_tx.htlcs().iter().enumerate()
trusted_tx.nondust_htlcs().iter().enumerate()
.find(|(_, htlc)| if let Some(output_index) = htlc.transaction_output_index {
output_index == outp.vout
} else {
@@ -1359,29 +1359,28 @@ mod tests {

// Create an OnchainTxHandler for a commitment containing HTLCs with CLTV expiries of 0, 1,
// and 2 blocks.
let mut htlcs = Vec::new();
let mut nondust_htlcs = Vec::new();
for i in 0..3 {
let preimage = PaymentPreimage([i; 32]);
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).to_byte_array());
htlcs.push((
nondust_htlcs.push(
HTLCOutputInCommitment {
offered: true,
amount_msat: 10000,
cltv_expiry: i as u32,
payment_hash: hash,
transaction_output_index: Some(i as u32),
},
(),
));
}
);
}
let holder_commit = HolderCommitmentTransaction::dummy(1000000, &mut htlcs);
let holder_commit = HolderCommitmentTransaction::dummy(1000000, &nondust_htlcs);
let mut tx_handler = OnchainTxHandler::new(
1000000,
[0; 32],
ScriptBuf::new(),
signer,
chan_params,
holder_commit,
holder_commit.clone(),
secp_ctx,
);

@@ -1400,7 +1399,7 @@ mod tests {
// Request claiming of each HTLC on the holder's commitment, with current block height 1.
let holder_commit_txid = tx_handler.get_unsigned_holder_commitment_tx().compute_txid();
let mut requests = Vec::new();
for (htlc, _) in htlcs {
for htlc in holder_commit.nondust_htlcs() {
requests.push(PackageTemplate::build_package(
holder_commit_txid,
htlc.transaction_output_index.unwrap(),
Loading