DRY the comparison blocks in update_claims_view_from_matched_txn

In `update_claims_view_from_matched_txn` we have two different
tx-equivalence checks which do the same thing - both check that the
tx which appeared on chain spent all of the outpoints which we
intended to spend in a given package. While one is more effecient
than the other (but only usable in a subset of cases), the
difference between O(N) and O(N^2) when N is 1-5 is trivial.

Still, it is possible we hit this code with just shy of 900 HTLC
outputs in a channel, and a transaction with a ton of inputs.

While having to spin through a few million entries if our
counterparty wastes a full block isn't really a big deal, we go
ahead and use a sorted vec and binary searches because its trivial.
This commit is contained in:
Matt Corallo 2022-12-07 00:30:43 +00:00
parent 399b3eb3f7
commit 60f3c0a206

View file

@ -733,31 +733,13 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
// outpoints to know if transaction is the original claim or a bumped one issued
// by us.
let mut are_sets_equal = true;
if !request.requires_external_funding() || !request.is_malleable() {
// If the claim does not require external funds to be allocated through
// additional inputs we can simply check the inputs in order as they
// cannot change under us.
if request.outpoints().len() != tx.input.len() {
let mut tx_inputs = tx.input.iter().map(|input| &input.previous_output).collect::<Vec<_>>();
tx_inputs.sort_unstable();
for request_input in request.outpoints() {
if tx_inputs.binary_search(&request_input).is_err() {
are_sets_equal = false;
} else {
for (claim_inp, tx_inp) in request.outpoints().iter().zip(tx.input.iter()) {
if **claim_inp != tx_inp.previous_output {
are_sets_equal = false;
}
}
break;
}
} else {
// Otherwise, we'll do a linear search for each input (we don't expect
// large input sets to exist) to ensure the request's input set is fully
// spent to be resilient against the external claim reordering inputs.
let mut spends_all_inputs = true;
for request_input in request.outpoints() {
if tx.input.iter().find(|input| input.previous_output == *request_input).is_none() {
spends_all_inputs = false;
break;
}
}
are_sets_equal = spends_all_inputs;
}
macro_rules! clean_claim_request_after_safety_delay {