make cut_through significantly more useful by returning both cut-through and non-cut-through elements (#3410)

split the slices internally rather than simply taking sub-slices
This commit is contained in:
Antioch Peverell 2020-07-30 15:29:20 +01:00 committed by GitHub
parent 83b269961a
commit 70c637fe4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 10 deletions

View file

@ -573,7 +573,7 @@ impl Block {
} }
// apply cut-through to our tx inputs and outputs // apply cut-through to our tx inputs and outputs
let (inputs, outputs) = transaction::cut_through(&mut inputs, &mut outputs)?; let (inputs, outputs, _, _) = transaction::cut_through(&mut inputs, &mut outputs)?;
let mut outputs = outputs.to_vec(); let mut outputs = outputs.to_vec();
let mut kernels = kernels.to_vec(); let mut kernels = kernels.to_vec();

View file

@ -1280,13 +1280,19 @@ impl Transaction {
} }
} }
/// Matches any output with a potential spending input, eliminating them /// Takes a slice of inputs and a slice of outputs and applies "cut-through"
/// from the Vec. Provides a simple way to cut-through a block or aggregated /// eliminating any input/output pairs with input spending output.
/// transaction. /// Returns new slices with cut-through elements removed.
/// Also returns slices of the cut-through elements themselves.
///
/// Example:
/// Inputs: [A, B, C]
/// Outputs: [C, D, E]
/// Returns: ([A, B], [D, E], [C], [C]) # element C is cut-through
pub fn cut_through<'a>( pub fn cut_through<'a>(
inputs: &'a mut [Input], inputs: &'a mut [Input],
outputs: &'a mut [Output], outputs: &'a mut [Output],
) -> Result<(&'a [Input], &'a [Output]), Error> { ) -> Result<(&'a [Input], &'a [Output], &'a [Input], &'a [Output]), Error> {
// Make sure inputs and outputs are sorted consistently by commitment. // Make sure inputs and outputs are sorted consistently by commitment.
inputs.sort_unstable_by_key(|x| x.commitment()); inputs.sort_unstable_by_key(|x| x.commitment());
outputs.sort_unstable_by_key(|x| x.commitment()); outputs.sort_unstable_by_key(|x| x.commitment());
@ -1327,9 +1333,15 @@ pub fn cut_through<'a>(
outputs_idx += 1; outputs_idx += 1;
} }
// Take new shorter slices with cut-through elements removed. // Split inputs and outputs slices into non-cut-through and cut-through slices.
let inputs = &inputs[..inputs.len() - ncut]; let (inputs, inputs_cut) = inputs.split_at_mut(inputs.len() - ncut);
let outputs = &outputs[..outputs.len() - ncut]; let (outputs, outputs_cut) = outputs.split_at_mut(outputs.len() - ncut);
// Resort all the new slices.
inputs.sort_unstable();
outputs.sort_unstable();
inputs_cut.sort_unstable();
outputs_cut.sort_unstable();
// Check we have no duplicate inputs after cut-through. // Check we have no duplicate inputs after cut-through.
if inputs.windows(2).any(|pair| pair[0] == pair[1]) { if inputs.windows(2).any(|pair| pair[0] == pair[1]) {
@ -1341,7 +1353,7 @@ pub fn cut_through<'a>(
return Err(Error::CutThrough); return Err(Error::CutThrough);
} }
Ok((inputs, outputs)) Ok((inputs, outputs, inputs_cut, outputs_cut))
} }
/// Aggregate a vec of txs into a multi-kernel tx with cut_through. /// Aggregate a vec of txs into a multi-kernel tx with cut_through.
@ -1378,7 +1390,7 @@ pub fn aggregate(txs: &[Transaction]) -> Result<Transaction, Error> {
kernels.extend_from_slice(tx.kernels()); kernels.extend_from_slice(tx.kernels());
} }
let (inputs, outputs) = cut_through(&mut inputs, &mut outputs)?; let (inputs, outputs, _, _) = cut_through(&mut inputs, &mut outputs)?;
// now sum the kernel_offsets up to give us an aggregate offset for the // now sum the kernel_offsets up to give us an aggregate offset for the
// transaction // transaction