pass slices around and not refs to vecs (#3404)

* pass slices around and not refs to vecs

* use slice.swap()

* use inputs() not body.inputs
This commit is contained in:
Antioch Peverell
2020-07-27 11:07:18 +01:00
committed by GitHub
parent 105f50b26b
commit 80841f16d2
29 changed files with 272 additions and 275 deletions
+19 -22
View File
@@ -538,7 +538,7 @@ impl Block {
#[warn(clippy::new_ret_no_self)]
pub fn new(
prev: &BlockHeader,
txs: Vec<Transaction>,
txs: &[Transaction],
difficulty: Difficulty,
reward_output: (Output, TxKernel),
) -> Result<Block, Error> {
@@ -557,7 +557,7 @@ impl Block {
/// Hydrate a block from a compact block.
/// Note: caller must validate the block themselves, we do not validate it
/// here.
pub fn hydrate_from(cb: CompactBlock, txs: Vec<Transaction>) -> Result<Block, Error> {
pub fn hydrate_from(cb: CompactBlock, txs: &[Transaction]) -> Result<Block, Error> {
trace!("block: hydrate_from: {}, {} txs", cb.hash(), txs.len(),);
let header = cb.header.clone();
@@ -568,10 +568,9 @@ impl Block {
// collect all the inputs, outputs and kernels from the txs
for tx in txs {
let tb: TransactionBody = tx.into();
all_inputs.extend(tb.inputs);
all_outputs.extend(tb.outputs);
all_kernels.extend(tb.kernels);
all_inputs.extend(tx.inputs());
all_outputs.extend(tx.outputs());
all_kernels.extend(tx.kernels());
}
// include the coinbase output(s) and kernel(s) from the compact_block
@@ -587,7 +586,7 @@ impl Block {
let all_kernels = Vec::from_iter(all_kernels);
// Initialize a tx body and sort everything.
let body = TransactionBody::init(all_inputs, all_outputs, all_kernels, false)?;
let body = TransactionBody::init(&all_inputs, &all_outputs, &all_kernels, false)?;
// Finally return the full block.
// Note: we have not actually validated the block here,
@@ -608,7 +607,7 @@ impl Block {
/// that all transactions are valid and calculates the Merkle tree.
pub fn from_reward(
prev: &BlockHeader,
txs: Vec<Transaction>,
txs: &[Transaction],
reward_out: Output,
reward_kern: TxKernel,
difficulty: Difficulty,
@@ -663,32 +662,32 @@ impl Block {
}
/// Get inputs
pub fn inputs(&self) -> &Vec<Input> {
pub fn inputs(&self) -> &[Input] {
&self.body.inputs
}
/// Get inputs mutable
pub fn inputs_mut(&mut self) -> &mut Vec<Input> {
pub fn inputs_mut(&mut self) -> &mut [Input] {
&mut self.body.inputs
}
/// Get outputs
pub fn outputs(&self) -> &Vec<Output> {
pub fn outputs(&self) -> &[Output] {
&self.body.outputs
}
/// Get outputs mutable
pub fn outputs_mut(&mut self) -> &mut Vec<Output> {
pub fn outputs_mut(&mut self) -> &mut [Output] {
&mut self.body.outputs
}
/// Get kernels
pub fn kernels(&self) -> &Vec<TxKernel> {
pub fn kernels(&self) -> &[TxKernel] {
&self.body.kernels
}
/// Get kernels mut
pub fn kernels_mut(&mut self) -> &mut Vec<TxKernel> {
pub fn kernels_mut(&mut self) -> &mut [TxKernel] {
&mut self.body.kernels
}
@@ -702,14 +701,12 @@ impl Block {
/// elimination is stable with respect to the order of inputs and outputs.
/// Method consumes the block.
pub fn cut_through(self) -> Result<Block, Error> {
let mut inputs = self.inputs().clone();
let mut outputs = self.outputs().clone();
transaction::cut_through(&mut inputs, &mut outputs)?;
let kernels = self.kernels().clone();
let mut inputs = self.inputs().to_vec();
let mut outputs = self.outputs().to_vec();
let (inputs, outputs) = transaction::cut_through(&mut inputs, &mut outputs)?;
// Initialize tx body and sort everything.
let body = TransactionBody::init(inputs, outputs, kernels, false)?;
let body = TransactionBody::init(inputs, outputs, self.kernels(), false)?;
Ok(Block {
header: self.header,
@@ -809,7 +806,7 @@ impl Block {
// Verify any absolute kernel lock heights.
fn verify_kernel_lock_heights(&self) -> Result<(), Error> {
for k in &self.body.kernels {
for k in self.kernels() {
// check we have no kernels with lock_heights greater than current height
// no tx can be included in a block earlier than its lock_height
if let KernelFeatures::HeightLocked { lock_height, .. } = k.features {
@@ -825,7 +822,7 @@ impl Block {
// NRD kernels were introduced in HF3 and are not valid for block version < 4.
// Blocks prior to HF3 containing any NRD kernel(s) are invalid.
fn verify_nrd_kernels_for_header_version(&self) -> Result<(), Error> {
if self.body.kernels.iter().any(|k| k.is_nrd()) {
if self.kernels().iter().any(|k| k.is_nrd()) {
if !global::is_nrd_enabled() {
return Err(Error::NRDKernelNotEnabled);
}
+3 -3
View File
@@ -146,17 +146,17 @@ impl CompactBlock {
}
/// Get kern_ids
pub fn kern_ids(&self) -> &Vec<ShortId> {
pub fn kern_ids(&self) -> &[ShortId] {
&self.body.kern_ids
}
/// Get full (coinbase) kernels
pub fn kern_full(&self) -> &Vec<TxKernel> {
pub fn kern_full(&self) -> &[TxKernel] {
&self.body.kern_full
}
/// Get full (coinbase) outputs
pub fn out_full(&self) -> &Vec<Output> {
pub fn out_full(&self) -> &[Output] {
&self.body.out_full
}
}
+67 -51
View File
@@ -440,7 +440,7 @@ impl From<committed::Error> for Error {
/// amount to zero.
/// The signature signs the fee and the lock_height, which are retained for
/// signature validation.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct TxKernel {
/// Options for a kernel's structure or use
pub features: KernelFeatures,
@@ -710,7 +710,7 @@ impl Readable for TransactionBody {
let kernels = read_multi(reader, kernel_len)?;
// Initialize tx body and verify everything is sorted.
let body = TransactionBody::init(inputs, outputs, kernels, true)
let body = TransactionBody::init(&inputs, &outputs, &kernels, true)
.map_err(|_| ser::Error::CorruptedData)?;
Ok(body)
@@ -737,6 +737,12 @@ impl Default for TransactionBody {
}
}
impl From<Transaction> for TransactionBody {
fn from(tx: Transaction) -> Self {
tx.body
}
}
impl TransactionBody {
/// Creates a new empty transaction (no inputs or outputs, zero fee).
pub fn empty() -> TransactionBody {
@@ -758,15 +764,15 @@ impl TransactionBody {
/// the provided inputs, outputs and kernels.
/// Guarantees inputs, outputs, kernels are sorted lexicographically.
pub fn init(
inputs: Vec<Input>,
outputs: Vec<Output>,
kernels: Vec<TxKernel>,
inputs: &[Input],
outputs: &[Output],
kernels: &[TxKernel],
verify_sorted: bool,
) -> Result<TransactionBody, Error> {
let mut body = TransactionBody {
inputs,
outputs,
kernels,
inputs: inputs.to_vec(),
outputs: outputs.to_vec(),
kernels: kernels.to_vec(),
};
if verify_sorted {
@@ -1075,12 +1081,6 @@ impl PartialEq for Transaction {
}
}
impl Into<TransactionBody> for Transaction {
fn into(self) -> TransactionBody {
self.body
}
}
/// Implementation of Writeable for a fully blinded transaction, defines how to
/// write the transaction as binary.
impl Writeable for Transaction {
@@ -1140,7 +1140,7 @@ impl Transaction {
/// Creates a new transaction initialized with
/// the provided inputs, outputs, kernels
pub fn new(inputs: Vec<Input>, outputs: Vec<Output>, kernels: Vec<TxKernel>) -> Transaction {
pub fn new(inputs: &[Input], outputs: &[Output], kernels: &[TxKernel]) -> Transaction {
let offset = BlindingFactor::zero();
// Initialize a new tx body and sort everything.
@@ -1195,32 +1195,32 @@ impl Transaction {
}
/// Get inputs
pub fn inputs(&self) -> &Vec<Input> {
pub fn inputs(&self) -> &[Input] {
&self.body.inputs
}
/// Get inputs mutable
pub fn inputs_mut(&mut self) -> &mut Vec<Input> {
pub fn inputs_mut(&mut self) -> &mut [Input] {
&mut self.body.inputs
}
/// Get outputs
pub fn outputs(&self) -> &Vec<Output> {
pub fn outputs(&self) -> &[Output] {
&self.body.outputs
}
/// Get outputs mutable
pub fn outputs_mut(&mut self) -> &mut Vec<Output> {
pub fn outputs_mut(&mut self) -> &mut [Output] {
&mut self.body.outputs
}
/// Get kernels
pub fn kernels(&self) -> &Vec<TxKernel> {
pub fn kernels(&self) -> &[TxKernel] {
&self.body.kernels
}
/// Get kernels mut
pub fn kernels_mut(&mut self) -> &mut Vec<TxKernel> {
pub fn kernels_mut(&mut self) -> &mut [TxKernel] {
&mut self.body.kernels
}
@@ -1290,7 +1290,10 @@ impl Transaction {
/// from the Vec. Provides a simple way to cut-through a block or aggregated
/// transaction. The elimination is stable with respect to the order of inputs
/// and outputs.
pub fn cut_through(inputs: &mut Vec<Input>, outputs: &mut Vec<Output>) -> Result<(), Error> {
pub fn cut_through<'a>(
inputs: &'a mut [Input],
outputs: &'a mut [Output],
) -> Result<(&'a [Input], &'a [Output]), Error> {
// assemble output commitments set, checking they're all unique
outputs.sort_unstable();
if outputs.windows(2).any(|pair| pair[0] == pair[1]) {
@@ -1303,11 +1306,11 @@ pub fn cut_through(inputs: &mut Vec<Input>, outputs: &mut Vec<Output>) -> Result
while inputs_idx < inputs.len() && outputs_idx < outputs.len() {
match inputs[inputs_idx].hash().cmp(&outputs[outputs_idx].hash()) {
Ordering::Less => {
inputs[inputs_idx - ncut] = inputs[inputs_idx];
inputs.swap(inputs_idx - ncut, inputs_idx);
inputs_idx += 1;
}
Ordering::Greater => {
outputs[outputs_idx - ncut] = outputs[outputs_idx];
outputs.swap(outputs_idx - ncut, outputs_idx);
outputs_idx += 1;
}
Ordering::Equal => {
@@ -1317,27 +1320,40 @@ pub fn cut_through(inputs: &mut Vec<Input>, outputs: &mut Vec<Output>) -> Result
}
}
}
// Cut elements that have already been copied
outputs.drain(outputs_idx - ncut..outputs_idx);
inputs.drain(inputs_idx - ncut..inputs_idx);
Ok(())
// Make sure we move any the remaining inputs into the slice to be returned.
while inputs_idx < inputs.len() {
inputs.swap(inputs_idx - ncut, inputs_idx);
inputs_idx += 1;
}
// Make sure we move any the remaining outputs into the slice to be returned.
while outputs_idx < outputs.len() {
outputs.swap(outputs_idx - ncut, outputs_idx);
outputs_idx += 1;
}
Ok((
&inputs[..inputs.len() - ncut],
&outputs[..outputs.len() - ncut],
))
}
/// Aggregate a vec of txs into a multi-kernel tx with cut_through.
pub fn aggregate(mut txs: Vec<Transaction>) -> Result<Transaction, Error> {
pub fn aggregate(txs: &[Transaction]) -> Result<Transaction, Error> {
// convenience short-circuiting
if txs.is_empty() {
return Ok(Transaction::empty());
} else if txs.len() == 1 {
return Ok(txs.pop().unwrap());
return Ok(txs[0].clone());
}
let mut n_inputs = 0;
let mut n_outputs = 0;
let mut n_kernels = 0;
for tx in txs.iter() {
n_inputs += tx.body.inputs.len();
n_outputs += tx.body.outputs.len();
n_kernels += tx.body.kernels.len();
n_inputs += tx.inputs().len();
n_outputs += tx.outputs().len();
n_kernels += tx.kernels().len();
}
let mut inputs: Vec<Input> = Vec::with_capacity(n_inputs);
@@ -1347,17 +1363,17 @@ pub fn aggregate(mut txs: Vec<Transaction>) -> Result<Transaction, Error> {
// we will sum these together at the end to give us the overall offset for the
// transaction
let mut kernel_offsets: Vec<BlindingFactor> = Vec::with_capacity(txs.len());
for mut tx in txs {
for tx in txs {
// we will sum these later to give a single aggregate offset
kernel_offsets.push(tx.offset);
kernel_offsets.push(tx.offset.clone());
inputs.append(&mut tx.body.inputs);
outputs.append(&mut tx.body.outputs);
kernels.append(&mut tx.body.kernels);
inputs.extend_from_slice(tx.inputs());
outputs.extend_from_slice(tx.outputs());
kernels.extend_from_slice(tx.kernels());
}
// Sort inputs and outputs during cut_through.
cut_through(&mut inputs, &mut outputs)?;
let (inputs, outputs) = cut_through(&mut inputs, &mut outputs)?;
// Now sort kernels.
kernels.sort_unstable();
@@ -1371,14 +1387,14 @@ pub fn aggregate(mut txs: Vec<Transaction>) -> Result<Transaction, Error> {
// * cut-through outputs
// * full set of tx kernels
// * sum of all kernel offsets
let tx = Transaction::new(inputs, outputs, kernels).with_offset(total_kernel_offset);
let tx = Transaction::new(inputs, outputs, &kernels).with_offset(total_kernel_offset);
Ok(tx)
}
/// Attempt to deaggregate a multi-kernel transaction based on multiple
/// transactions
pub fn deaggregate(mk_tx: Transaction, txs: Vec<Transaction>) -> Result<Transaction, Error> {
pub fn deaggregate(mk_tx: Transaction, txs: &[Transaction]) -> Result<Transaction, Error> {
let mut inputs: Vec<Input> = vec![];
let mut outputs: Vec<Output> = vec![];
let mut kernels: Vec<TxKernel> = vec![];
@@ -1389,19 +1405,19 @@ pub fn deaggregate(mk_tx: Transaction, txs: Vec<Transaction>) -> Result<Transact
let tx = aggregate(txs)?;
for mk_input in mk_tx.body.inputs {
if !tx.body.inputs.contains(&mk_input) && !inputs.contains(&mk_input) {
inputs.push(mk_input);
for mk_input in mk_tx.inputs() {
if !tx.inputs().contains(&mk_input) && !inputs.contains(mk_input) {
inputs.push(*mk_input);
}
}
for mk_output in mk_tx.body.outputs {
if !tx.body.outputs.contains(&mk_output) && !outputs.contains(&mk_output) {
outputs.push(mk_output);
for mk_output in mk_tx.outputs() {
if !tx.outputs().contains(&mk_output) && !outputs.contains(mk_output) {
outputs.push(*mk_output);
}
}
for mk_kernel in mk_tx.body.kernels {
if !tx.body.kernels.contains(&mk_kernel) && !kernels.contains(&mk_kernel) {
kernels.push(mk_kernel);
for mk_kernel in mk_tx.kernels() {
if !tx.kernels().contains(&mk_kernel) && !kernels.contains(mk_kernel) {
kernels.push(*mk_kernel);
}
}
@@ -1436,7 +1452,7 @@ pub fn deaggregate(mk_tx: Transaction, txs: Vec<Transaction>) -> Result<Transact
kernels.sort_unstable();
// Build a new tx from the above data.
let tx = Transaction::new(inputs, outputs, kernels).with_offset(total_kernel_offset);
let tx = Transaction::new(&inputs, &outputs, &kernels).with_offset(total_kernel_offset);
Ok(tx)
}
+6 -6
View File
@@ -182,7 +182,7 @@ where
///
pub fn partial_transaction<K, B>(
tx: Transaction,
elems: Vec<Box<Append<K, B>>>,
elems: &[Box<Append<K, B>>],
keychain: &K,
builder: &B,
) -> Result<(Transaction, BlindingFactor), Error>
@@ -203,7 +203,7 @@ where
/// In the real world we use signature aggregation across multiple participants.
pub fn transaction<K, B>(
features: KernelFeatures,
elems: Vec<Box<Append<K, B>>>,
elems: &[Box<Append<K, B>>],
keychain: &K,
builder: &B,
) -> Result<Transaction, Error>
@@ -230,7 +230,7 @@ where
/// NOTE: Only used in tests (for convenience).
/// Cannot recommend passing private excess around like this in the real world.
pub fn transaction_with_kernel<K, B>(
elems: Vec<Box<Append<K, B>>>,
elems: &[Box<Append<K, B>>],
kernel: TxKernel,
excess: BlindingFactor,
keychain: &K,
@@ -284,7 +284,7 @@ mod test {
let tx = transaction(
KernelFeatures::Plain { fee: 2 },
vec![input(10, key_id1), input(12, key_id2), output(20, key_id3)],
&[input(10, key_id1), input(12, key_id2), output(20, key_id3)],
&keychain,
&builder,
)
@@ -306,7 +306,7 @@ mod test {
let tx = transaction(
KernelFeatures::Plain { fee: 2 },
vec![input(10, key_id1), input(12, key_id2), output(20, key_id3)],
&[input(10, key_id1), input(12, key_id2), output(20, key_id3)],
&keychain,
&builder,
)
@@ -327,7 +327,7 @@ mod test {
let tx = transaction(
KernelFeatures::Plain { fee: 4 },
vec![input(6, key_id1), output(2, key_id2)],
&[input(6, key_id1), output(2, key_id2)],
&keychain,
&builder,
)