mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
no need to rehash with index to compare output with input spending it (#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
This commit is contained in:
parent
2527006e8d
commit
5f5b1d2f13
5 changed files with 32 additions and 42 deletions
|
@ -288,7 +288,7 @@ impl OutputPrintable {
|
||||||
OutputType::Transaction
|
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 res = chain.is_unspent(&out_id);
|
||||||
let (spent, block_height) = if let Ok(output_pos) = res {
|
let (spent, block_height) = if let Ok(output_pos) = res {
|
||||||
(false, Some(output_pos.height))
|
(false, Some(output_pos.height))
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::core::core::hash::{Hash, Hashed};
|
||||||
use crate::core::core::merkle_proof::MerkleProof;
|
use crate::core::core::merkle_proof::MerkleProof;
|
||||||
use crate::core::core::pmmr::{self, Backend, ReadonlyPMMR, RewindablePMMR, PMMR};
|
use crate::core::core::pmmr::{self, Backend, ReadonlyPMMR, RewindablePMMR, PMMR};
|
||||||
use crate::core::core::{Block, BlockHeader, Input, Output, OutputIdentifier, TxKernel};
|
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::error::{Error, ErrorKind};
|
||||||
use crate::store::{Batch, ChainStore};
|
use crate::store::{Batch, ChainStore};
|
||||||
use crate::txhashset::bitmap_accumulator::BitmapAccumulator;
|
use crate::txhashset::bitmap_accumulator::BitmapAccumulator;
|
||||||
|
@ -229,11 +229,11 @@ impl TxHashSet {
|
||||||
Ok((pos, height)) => {
|
Ok((pos, height)) => {
|
||||||
let output_pmmr: ReadonlyPMMR<'_, Output, _> =
|
let output_pmmr: ReadonlyPMMR<'_, Output, _> =
|
||||||
ReadonlyPMMR::at(&self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
ReadonlyPMMR::at(&self.output_pmmr_h.backend, self.output_pmmr_h.last_pos);
|
||||||
if let Some(hash) = output_pmmr.get_hash(pos) {
|
if let Some(out) = output_pmmr.get_data(pos) {
|
||||||
if hash == output_id.hash_with_index(pos - 1) {
|
if OutputIdentifier::from(out) == *output_id {
|
||||||
Ok(CommitPos { pos, height })
|
Ok(CommitPos { pos, height })
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorKind::TxHashSetErr("txhashset hash mismatch".to_string()).into())
|
Err(ErrorKind::TxHashSetErr("txhashset mismatch".to_string()).into())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorKind::OutputNotFound.into())
|
Err(ErrorKind::OutputNotFound.into())
|
||||||
|
@ -984,11 +984,9 @@ impl<'a> Extension<'a> {
|
||||||
let commit = input.commitment();
|
let commit = input.commitment();
|
||||||
if let Ok((pos, height)) = batch.get_output_pos_height(&commit) {
|
if let Ok((pos, height)) = batch.get_output_pos_height(&commit) {
|
||||||
// First check this input corresponds to an existing entry in the output MMR.
|
// First check this input corresponds to an existing entry in the output MMR.
|
||||||
if let Some(hash) = self.output_pmmr.get_hash(pos) {
|
if let Some(out) = self.output_pmmr.get_data(pos) {
|
||||||
if hash != input.hash_with_index(pos - 1) {
|
if OutputIdentifier::from(input) != out {
|
||||||
return Err(
|
return Err(ErrorKind::TxHashSetErr("output pmmr mismatch".to_string()).into());
|
||||||
ErrorKind::TxHashSetErr("output pmmr hash mismatch".to_string()).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
use crate::core::core::hash::{Hash, Hashed};
|
use crate::core::core::hash::{Hash, Hashed};
|
||||||
use crate::core::core::pmmr::{self, ReadonlyPMMR};
|
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::global;
|
||||||
use crate::core::ser::PMMRIndexHashable;
|
|
||||||
use crate::error::{Error, ErrorKind};
|
use crate::error::{Error, ErrorKind};
|
||||||
use crate::store::Batch;
|
use crate::store::Batch;
|
||||||
use crate::util::secp::pedersen::RangeProof;
|
use crate::util::secp::pedersen::RangeProof;
|
||||||
|
@ -75,11 +74,11 @@ impl<'a> UTXOView<'a> {
|
||||||
|
|
||||||
// Input is valid if it is spending an (unspent) output
|
// Input is valid if it is spending an (unspent) output
|
||||||
// that currently exists in the output MMR.
|
// 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> {
|
fn validate_input(&self, input: &Input, batch: &Batch<'_>) -> Result<(), Error> {
|
||||||
if let Ok(pos) = batch.get_output_pos(&input.commitment()) {
|
if let Ok(pos) = batch.get_output_pos(&input.commitment()) {
|
||||||
if let Some(hash) = self.output_pmmr.get_hash(pos) {
|
if let Some(out) = self.output_pmmr.get_data(pos) {
|
||||||
if hash == input.hash_with_index(pos - 1) {
|
if OutputIdentifier::from(input) == out {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,7 +546,7 @@ fn spend_rewind_spend() {
|
||||||
// mine the first block and keep track of the block_hash
|
// mine the first block and keep track of the block_hash
|
||||||
// so we can spend the coinbase later
|
// so we can spend the coinbase later
|
||||||
let b = prepare_block_key_idx(&kc, &head, &chain, 2, 1);
|
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());
|
assert!(out_id.features.is_coinbase());
|
||||||
head = b.header.clone();
|
head = b.header.clone();
|
||||||
chain
|
chain
|
||||||
|
@ -620,7 +620,7 @@ fn spend_in_fork_and_compact() {
|
||||||
// mine the first block and keep track of the block_hash
|
// mine the first block and keep track of the block_hash
|
||||||
// so we can spend the coinbase later
|
// so we can spend the coinbase later
|
||||||
let b = prepare_block(&kc, &fork_head, &chain, 2);
|
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());
|
assert!(out_id.features.is_coinbase());
|
||||||
fork_head = b.header.clone();
|
fork_head = b.header.clone();
|
||||||
chain
|
chain
|
||||||
|
@ -694,10 +694,10 @@ fn spend_in_fork_and_compact() {
|
||||||
assert_eq!(head.height, 6);
|
assert_eq!(head.height, 6);
|
||||||
assert_eq!(head.hash(), prev_main.hash());
|
assert_eq!(head.hash(), prev_main.hash());
|
||||||
assert!(chain
|
assert!(chain
|
||||||
.is_unspent(&OutputIdentifier::from_output(&tx2.outputs()[0]))
|
.is_unspent(&OutputIdentifier::from(&tx2.outputs()[0]))
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(chain
|
assert!(chain
|
||||||
.is_unspent(&OutputIdentifier::from_output(&tx1.outputs()[0]))
|
.is_unspent(&OutputIdentifier::from(&tx1.outputs()[0]))
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
// make the fork win
|
// make the fork win
|
||||||
|
@ -713,10 +713,10 @@ fn spend_in_fork_and_compact() {
|
||||||
assert_eq!(head.height, 7);
|
assert_eq!(head.height, 7);
|
||||||
assert_eq!(head.hash(), prev_fork.hash());
|
assert_eq!(head.hash(), prev_fork.hash());
|
||||||
assert!(chain
|
assert!(chain
|
||||||
.is_unspent(&OutputIdentifier::from_output(&tx2.outputs()[0]))
|
.is_unspent(&OutputIdentifier::from(&tx2.outputs()[0]))
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(chain
|
assert!(chain
|
||||||
.is_unspent(&OutputIdentifier::from_output(&tx1.outputs()[0]))
|
.is_unspent(&OutputIdentifier::from(&tx1.outputs()[0]))
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
// add 20 blocks to go past the test horizon
|
// add 20 blocks to go past the test horizon
|
||||||
|
@ -790,7 +790,7 @@ fn output_header_mappings() {
|
||||||
chain.process_block(b, chain::Options::MINE).unwrap();
|
chain.process_block(b, chain::Options::MINE).unwrap();
|
||||||
|
|
||||||
let header_for_output = chain
|
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();
|
.unwrap();
|
||||||
assert_eq!(header_for_output.height, n as u64);
|
assert_eq!(header_for_output.height, n as u64);
|
||||||
|
|
||||||
|
@ -800,7 +800,7 @@ fn output_header_mappings() {
|
||||||
// Check all output positions are as expected
|
// Check all output positions are as expected
|
||||||
for n in 1..15 {
|
for n in 1..15 {
|
||||||
let header_for_output = chain
|
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();
|
.unwrap();
|
||||||
assert_eq!(header_for_output.height, n as u64);
|
assert_eq!(header_for_output.height, n as u64);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1424,7 +1424,7 @@ impl PMMRable for Output {
|
||||||
type E = OutputIdentifier;
|
type E = OutputIdentifier;
|
||||||
|
|
||||||
fn as_elmt(&self) -> OutputIdentifier {
|
fn as_elmt(&self) -> OutputIdentifier {
|
||||||
OutputIdentifier::from_output(self)
|
OutputIdentifier::from(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elmt_size() -> Option<u16> {
|
fn elmt_size() -> Option<u16> {
|
||||||
|
@ -1515,14 +1515,6 @@ impl OutputIdentifier {
|
||||||
self.commit
|
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
|
/// Converts this identifier to a full output, provided a RangeProof
|
||||||
pub fn into_output(self, proof: RangeProof) -> Output {
|
pub fn into_output(self, proof: RangeProof) -> Output {
|
||||||
Output {
|
Output {
|
||||||
|
@ -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.
|
/// convert an output_identifier to hex string format.
|
||||||
pub fn to_hex(&self) -> String {
|
pub fn to_hex(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
|
@ -1567,8 +1551,8 @@ impl Readable for OutputIdentifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Output> for OutputIdentifier {
|
impl From<&Output> for OutputIdentifier {
|
||||||
fn from(out: Output) -> Self {
|
fn from(out: &Output) -> Self {
|
||||||
OutputIdentifier {
|
OutputIdentifier {
|
||||||
features: out.features,
|
features: out.features,
|
||||||
commit: out.commit,
|
commit: out.commit,
|
||||||
|
@ -1576,6 +1560,15 @@ impl From<Output> for OutputIdentifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Input> for OutputIdentifier {
|
||||||
|
fn from(input: &Input) -> Self {
|
||||||
|
OutputIdentifier {
|
||||||
|
features: input.features,
|
||||||
|
commit: input.commit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in a new issue