Skip to content

Commit

Permalink
no need to rehash with index to compare output with input spending it (
Browse files Browse the repository at this point in the history
…#3260)

* no need to rehash with index to compare output with input spending it

* compare output identifier when checking is_unspent()

* output identifier from cleanup
  • Loading branch information
antiochp authored Mar 4, 2020
1 parent 2527006 commit 5f5b1d2
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 42 deletions.
2 changes: 1 addition & 1 deletion api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ impl OutputPrintable {
OutputType::Transaction
};

let out_id = core::OutputIdentifier::from_output(&output);
let out_id = core::OutputIdentifier::from(output);
let res = chain.is_unspent(&out_id);
let (spent, block_height) = if let Ok(output_pos) = res {
(false, Some(output_pos.height))
Expand Down
16 changes: 7 additions & 9 deletions chain/src/txhashset/txhashset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::core::core::hash::{Hash, Hashed};
use crate::core::core::merkle_proof::MerkleProof;
use crate::core::core::pmmr::{self, Backend, ReadonlyPMMR, RewindablePMMR, PMMR};
use crate::core::core::{Block, BlockHeader, Input, Output, OutputIdentifier, TxKernel};
use crate::core::ser::{PMMRIndexHashable, PMMRable, ProtocolVersion};
use crate::core::ser::{PMMRable, ProtocolVersion};
use crate::error::{Error, ErrorKind};
use crate::store::{Batch, ChainStore};
use crate::txhashset::bitmap_accumulator::BitmapAccumulator;
Expand Down Expand Up @@ -229,11 +229,11 @@ impl TxHashSet {
Ok((pos, height)) => {
let output_pmmr: ReadonlyPMMR<'_, Output, _> =
ReadonlyPMMR::at(&self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
if let Some(hash) = output_pmmr.get_hash(pos) {
if hash == output_id.hash_with_index(pos - 1) {
if let Some(out) = output_pmmr.get_data(pos) {
if OutputIdentifier::from(out) == *output_id {
Ok(CommitPos { pos, height })
} else {
Err(ErrorKind::TxHashSetErr("txhashset hash mismatch".to_string()).into())
Err(ErrorKind::TxHashSetErr("txhashset mismatch".to_string()).into())
}
} else {
Err(ErrorKind::OutputNotFound.into())
Expand Down Expand Up @@ -984,11 +984,9 @@ impl<'a> Extension<'a> {
let commit = input.commitment();
if let Ok((pos, height)) = batch.get_output_pos_height(&commit) {
// First check this input corresponds to an existing entry in the output MMR.
if let Some(hash) = self.output_pmmr.get_hash(pos) {
if hash != input.hash_with_index(pos - 1) {
return Err(
ErrorKind::TxHashSetErr("output pmmr hash mismatch".to_string()).into(),
);
if let Some(out) = self.output_pmmr.get_data(pos) {
if OutputIdentifier::from(input) != out {
return Err(ErrorKind::TxHashSetErr("output pmmr mismatch".to_string()).into());
}
}

Expand Down
9 changes: 4 additions & 5 deletions chain/src/txhashset/utxo_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
use crate::core::core::hash::{Hash, Hashed};
use crate::core::core::pmmr::{self, ReadonlyPMMR};
use crate::core::core::{Block, BlockHeader, Input, Output, Transaction};
use crate::core::core::{Block, BlockHeader, Input, Output, OutputIdentifier, Transaction};
use crate::core::global;
use crate::core::ser::PMMRIndexHashable;
use crate::error::{Error, ErrorKind};
use crate::store::Batch;
use crate::util::secp::pedersen::RangeProof;
Expand Down Expand Up @@ -75,11 +74,11 @@ impl<'a> UTXOView<'a> {

// Input is valid if it is spending an (unspent) output
// that currently exists in the output MMR.
// Compare the hash in the output MMR at the expected pos.
// Compare against the entry in output MMR at the expected pos.
fn validate_input(&self, input: &Input, batch: &Batch<'_>) -> Result<(), Error> {
if let Ok(pos) = batch.get_output_pos(&input.commitment()) {
if let Some(hash) = self.output_pmmr.get_hash(pos) {
if hash == input.hash_with_index(pos - 1) {
if let Some(out) = self.output_pmmr.get_data(pos) {
if OutputIdentifier::from(input) == out {
return Ok(());
}
}
Expand Down
16 changes: 8 additions & 8 deletions chain/tests/mine_simple_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ fn spend_rewind_spend() {
// mine the first block and keep track of the block_hash
// so we can spend the coinbase later
let b = prepare_block_key_idx(&kc, &head, &chain, 2, 1);
let out_id = OutputIdentifier::from_output(&b.outputs()[0]);
let out_id = OutputIdentifier::from(&b.outputs()[0]);
assert!(out_id.features.is_coinbase());
head = b.header.clone();
chain
Expand Down Expand Up @@ -620,7 +620,7 @@ fn spend_in_fork_and_compact() {
// mine the first block and keep track of the block_hash
// so we can spend the coinbase later
let b = prepare_block(&kc, &fork_head, &chain, 2);
let out_id = OutputIdentifier::from_output(&b.outputs()[0]);
let out_id = OutputIdentifier::from(&b.outputs()[0]);
assert!(out_id.features.is_coinbase());
fork_head = b.header.clone();
chain
Expand Down Expand Up @@ -694,10 +694,10 @@ fn spend_in_fork_and_compact() {
assert_eq!(head.height, 6);
assert_eq!(head.hash(), prev_main.hash());
assert!(chain
.is_unspent(&OutputIdentifier::from_output(&tx2.outputs()[0]))
.is_unspent(&OutputIdentifier::from(&tx2.outputs()[0]))
.is_ok());
assert!(chain
.is_unspent(&OutputIdentifier::from_output(&tx1.outputs()[0]))
.is_unspent(&OutputIdentifier::from(&tx1.outputs()[0]))
.is_err());

// make the fork win
Expand All @@ -713,10 +713,10 @@ fn spend_in_fork_and_compact() {
assert_eq!(head.height, 7);
assert_eq!(head.hash(), prev_fork.hash());
assert!(chain
.is_unspent(&OutputIdentifier::from_output(&tx2.outputs()[0]))
.is_unspent(&OutputIdentifier::from(&tx2.outputs()[0]))
.is_ok());
assert!(chain
.is_unspent(&OutputIdentifier::from_output(&tx1.outputs()[0]))
.is_unspent(&OutputIdentifier::from(&tx1.outputs()[0]))
.is_err());

// add 20 blocks to go past the test horizon
Expand Down Expand Up @@ -790,7 +790,7 @@ fn output_header_mappings() {
chain.process_block(b, chain::Options::MINE).unwrap();

let header_for_output = chain
.get_header_for_output(&OutputIdentifier::from_output(&reward_outputs[n - 1]))
.get_header_for_output(&OutputIdentifier::from(&reward_outputs[n - 1]))
.unwrap();
assert_eq!(header_for_output.height, n as u64);

Expand All @@ -800,7 +800,7 @@ fn output_header_mappings() {
// Check all output positions are as expected
for n in 1..15 {
let header_for_output = chain
.get_header_for_output(&OutputIdentifier::from_output(&reward_outputs[n - 1]))
.get_header_for_output(&OutputIdentifier::from(&reward_outputs[n - 1]))
.unwrap();
assert_eq!(header_for_output.height, n as u64);
}
Expand Down
31 changes: 12 additions & 19 deletions core/src/core/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ impl PMMRable for Output {
type E = OutputIdentifier;

fn as_elmt(&self) -> OutputIdentifier {
OutputIdentifier::from_output(self)
OutputIdentifier::from(self)
}

fn elmt_size() -> Option<u16> {
Expand Down Expand Up @@ -1515,14 +1515,6 @@ impl OutputIdentifier {
self.commit
}

/// Build an output_identifier from an existing output.
pub fn from_output(output: &Output) -> OutputIdentifier {
OutputIdentifier {
features: output.features,
commit: output.commit,
}
}

/// Converts this identifier to a full output, provided a RangeProof
pub fn into_output(self, proof: RangeProof) -> Output {
Output {
Expand All @@ -1532,14 +1524,6 @@ impl OutputIdentifier {
}
}

/// Build an output_identifier from an existing input.
pub fn from_input(input: &Input) -> OutputIdentifier {
OutputIdentifier {
features: input.features,
commit: input.commit,
}
}

/// convert an output_identifier to hex string format.
pub fn to_hex(&self) -> String {
format!(
Expand Down Expand Up @@ -1567,15 +1551,24 @@ impl Readable for OutputIdentifier {
}
}

impl From<Output> for OutputIdentifier {
fn from(out: Output) -> Self {
impl From<&Output> for OutputIdentifier {
fn from(out: &Output) -> Self {
OutputIdentifier {
features: out.features,
commit: out.commit,
}
}
}

impl From<&Input> for OutputIdentifier {
fn from(input: &Input) -> Self {
OutputIdentifier {
features: input.features,
commit: input.commit,
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down

0 comments on commit 5f5b1d2

Please sign in to comment.