diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 125246cc1f..0c2f38fd1b 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -30,7 +30,7 @@ use crate::store; use crate::txhashset; use crate::txhashset::{PMMRHandle, TxHashSet}; use crate::types::{ - BlockStatus, ChainAdapter, NoStatus, Options, OutputPos, Tip, TxHashsetWriteStatus, + BlockStatus, ChainAdapter, CommitPos, NoStatus, Options, Tip, TxHashsetWriteStatus, }; use crate::util::secp::pedersen::{Commitment, RangeProof}; use crate::util::RwLock; @@ -504,7 +504,7 @@ impl Chain { /// spent. This querying is done in a way that is consistent with the /// current chain state, specifically the current winning (valid, most /// work) fork. - pub fn is_unspent(&self, output_ref: &OutputIdentifier) -> Result { + pub fn is_unspent(&self, output_ref: &OutputIdentifier) -> Result { self.txhashset.read().is_unspent(output_ref) } diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index b8351a2701..2161dd71c5 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -23,7 +23,7 @@ use crate::core::pow; use crate::error::{Error, ErrorKind}; use crate::store; use crate::txhashset; -use crate::types::{Options, OutputPos, Tip}; +use crate::types::{CommitPos, Options, Tip}; use crate::util::RwLock; use grin_store; use std::sync::Arc; @@ -431,7 +431,7 @@ fn apply_block_to_txhashset( block: &Block, ext: &mut txhashset::ExtensionPair<'_>, batch: &store::Batch<'_>, -) -> Result, Error> { +) -> Result, Error> { let spent = ext.extension.apply_block(block, batch)?; ext.extension.validate_roots(&block.header)?; ext.extension.validate_sizes(&block.header)?; @@ -444,7 +444,7 @@ fn apply_block_to_txhashset( fn add_block( b: &Block, block_sums: &BlockSums, - spent: &Vec, + spent: &Vec, batch: &store::Batch<'_>, ) -> Result<(), Error> { batch.save_block(b)?; diff --git a/chain/src/store.rs b/chain/src/store.rs index 9abe73e7e5..3ea7c94c2e 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -19,7 +19,7 @@ use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::{Block, BlockHeader, BlockSums}; use crate::core::pow::Difficulty; use crate::core::ser::ProtocolVersion; -use crate::types::{OutputPos, Tip}; +use crate::types::{CommitPos, Tip}; use crate::util::secp::pedersen::Commitment; use croaring::Bitmap; use grin_store as store; @@ -190,7 +190,7 @@ impl<'a> Batch<'a> { /// We maintain a "spent" index for each full block to allow the output_pos /// to be easily reverted during rewind. - pub fn save_spent_index(&self, h: &Hash, spent: &Vec) -> Result<(), Error> { + pub fn save_spent_index(&self, h: &Hash, spent: &Vec) -> Result<(), Error> { self.db .put_ser(&to_key(BLOCK_SPENT_PREFIX, &mut h.to_vec())[..], spent)?; Ok(()) @@ -349,7 +349,7 @@ impl<'a> Batch<'a> { /// Get the "spent index" from the db for the specified block. /// If we need to rewind a block then we use this to "unspend" the spent outputs. - pub fn get_spent_index(&self, bh: &Hash) -> Result, Error> { + pub fn get_spent_index(&self, bh: &Hash) -> Result, Error> { option_to_not_found( self.db .get_ser(&to_key(BLOCK_SPENT_PREFIX, &mut bh.to_vec())), diff --git a/chain/src/txhashset/txhashset.rs b/chain/src/txhashset/txhashset.rs index d4f1a434c4..140d3f3ce8 100644 --- a/chain/src/txhashset/txhashset.rs +++ b/chain/src/txhashset/txhashset.rs @@ -25,7 +25,7 @@ use crate::error::{Error, ErrorKind}; use crate::store::{Batch, ChainStore}; use crate::txhashset::bitmap_accumulator::BitmapAccumulator; use crate::txhashset::{RewindableKernelView, UTXOView}; -use crate::types::{OutputPos, OutputRoots, Tip, TxHashSetRoots, TxHashsetWriteStatus}; +use crate::types::{CommitPos, OutputRoots, Tip, TxHashSetRoots, TxHashsetWriteStatus}; use crate::util::secp::pedersen::{Commitment, RangeProof}; use crate::util::{file, secp_static, zip}; use croaring::Bitmap; @@ -223,7 +223,7 @@ impl TxHashSet { /// Check if an output is unspent. /// We look in the index to find the output MMR pos. /// Then we check the entry in the output MMR and confirm the hash matches. - pub fn is_unspent(&self, output_id: &OutputIdentifier) -> Result { + pub fn is_unspent(&self, output_id: &OutputIdentifier) -> Result { let commit = output_id.commit; match self.commit_index.get_output_pos_height(&commit) { Ok((pos, height)) => { @@ -231,11 +231,7 @@ impl TxHashSet { 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) { - Ok(OutputPos { - pos, - height, - commit, - }) + Ok(CommitPos { pos, height }) } else { Err(ErrorKind::TxHashSetErr("txhashset hash mismatch".to_string()).into()) } @@ -927,27 +923,28 @@ impl<'a> Extension<'a> { } /// Apply a new block to the current txhashet extension (output, rangeproof, kernel MMRs). - pub fn apply_block(&mut self, b: &Block, batch: &Batch<'_>) -> Result, Error> { + /// Returns a vec of commit_pos representing the pos and height of the outputs spent + /// by this block. + pub fn apply_block(&mut self, b: &Block, batch: &Batch<'_>) -> Result, Error> { let mut affected_pos = vec![]; let mut spent = vec![]; + // Apply the output to the output and rangeproof MMRs. + // Add pos to affected_pos to update the accumulator later on. + // Add the new output to the output_pos index. for out in b.outputs() { let pos = self.apply_output(out, batch)?; affected_pos.push(pos); - - // TODO - we do *not* want to actually add to batch here? - // if we are processing a fork we want this batch to rollback. batch.save_output_pos_height(&out.commitment(), pos, b.header.height)?; } + // Remove the output from the output and rangeproof MMRs. + // Add spent_pos to affected_pos to update the accumulator later on. + // Remove the spent output from the output_pos index. for input in b.inputs() { let spent_pos = self.apply_input(input, batch)?; affected_pos.push(spent_pos.pos); - - // TODO - we do *not* want to actually add to batch here? - // if processing a fork we want this batch to rollback. - batch.delete_output_pos_height(&spent_pos.commit)?; - + batch.delete_output_pos_height(&input.commitment())?; spent.push(spent_pos); } @@ -965,9 +962,6 @@ impl<'a> Extension<'a> { } fn apply_to_bitmap_accumulator(&mut self, output_pos: &[u64]) -> Result<(), Error> { - // if self.output_pmmr.is_empty() || output_pos.is_empty() { - // return Ok(()); - // } let mut output_idx: Vec<_> = output_pos .iter() .map(|x| pmmr::n_leaves(*x).saturating_sub(1)) @@ -983,7 +977,7 @@ impl<'a> Extension<'a> { ) } - fn apply_input(&mut self, input: &Input, batch: &Batch<'_>) -> Result { + fn apply_input(&mut self, input: &Input, batch: &Batch<'_>) -> Result { 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. @@ -1003,11 +997,7 @@ impl<'a> Extension<'a> { self.rproof_pmmr .prune(pos) .map_err(ErrorKind::TxHashSetErr)?; - Ok(OutputPos { - pos, - height, - commit, - }) + Ok(CommitPos { pos, height }) } Ok(false) => Err(ErrorKind::AlreadySpent(commit).into()), Err(e) => Err(ErrorKind::TxHashSetErr(e).into()), @@ -1185,8 +1175,8 @@ impl<'a> Extension<'a> { // reused output commitment. For example an output at pos 1, spent, reused at pos 2. // The output_pos index should be updated to reflect the old pos 1 when unspent. if let Ok(spent) = spent { - for x in spent { - batch.save_output_pos_height(&x.commit, x.pos, x.height)?; + for (x, y) in block.inputs().into_iter().zip(spent) { + batch.save_output_pos_height(&x.commitment(), y.pos, y.height)?; } } diff --git a/chain/src/types.rs b/chain/src/types.rs index 96f3d6d699..be2d612bed 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -271,24 +271,27 @@ pub struct OutputPos { pub commit: Commitment, } -impl Readable for OutputPos { - fn read(reader: &mut dyn Reader) -> Result { +/// Minimal struct representing a known MMR position and associated block height. +#[derive(Debug)] +pub struct CommitPos { + /// MMR position + pub pos: u64, + /// Block height + pub height: u64, +} + +impl Readable for CommitPos { + fn read(reader: &mut dyn Reader) -> Result { let pos = reader.read_u64()?; let height = reader.read_u64()?; - let commit = Commitment::read(reader)?; - Ok(OutputPos { - pos, - height, - commit, - }) + Ok(CommitPos { pos, height }) } } -impl Writeable for OutputPos { +impl Writeable for CommitPos { fn write(&self, writer: &mut W) -> Result<(), ser::Error> { writer.write_u64(self.pos)?; writer.write_u64(self.height)?; - self.commit.write(writer)?; Ok(()) } }