diff --git a/chain/src/store.rs b/chain/src/store.rs index ac80d79e0..1b17d9ee9 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -14,9 +14,11 @@ //! Implements storage primitives required by the chain +use secp::pedersen::Commitment; + use types::*; use core::core::hash::{Hash, Hashed}; -use core::core::{Block, BlockHeader}; +use core::core::{Block, BlockHeader, Output}; use grin_store::{self, Error, to_key, u64_to_key, option_to_not_found}; const STORE_SUBPATH: &'static str = "chain"; @@ -26,6 +28,8 @@ const BLOCK_PREFIX: u8 = 'b' as u8; const HEAD_PREFIX: u8 = 'H' as u8; const HEADER_HEAD_PREFIX: u8 = 'I' as u8; const HEADER_HEIGHT_PREFIX: u8 = '8' as u8; +const OUTPUT_PREFIX: u8 = 'O' as u8; +const OUTPUT_COMMIT_PREFIX: u8 = 'o' as u8; /// An implementation of the ChainStore trait backed by a simple key-value /// store. @@ -75,12 +79,20 @@ impl ChainStore for ChainKVStore { } fn save_block(&self, b: &Block) -> Result<(), Error> { - self.db + // saving the block and its header + let mut batch = self.db .batch() .put_ser(&to_key(BLOCK_PREFIX, &mut b.hash().to_vec())[..], b)? .put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..], - &b.header)? - .write() + &b.header)?; + + // saving the full output under its hash, as well as a commitment to hash index + for out in &b.outputs { + batch = batch.put_ser(&to_key(OUTPUT_PREFIX, &mut out.hash().to_vec())[..], out)? + .put_ser(&to_key(OUTPUT_COMMIT_PREFIX, &mut out.commit.as_ref().to_vec())[..], + &out.hash())?; + } + batch.write() } fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> { @@ -92,6 +104,15 @@ impl ChainStore for ChainKVStore { option_to_not_found(self.db.get_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, height))) } + fn get_output(&self, h: &Hash) -> Result { + option_to_not_found(self.db.get_ser(&to_key(OUTPUT_PREFIX, &mut h.to_vec()))) + } + + fn has_output_commit(&self, commit: &Commitment) -> Result { + option_to_not_found(self.db + .get_ser(&to_key(OUTPUT_COMMIT_PREFIX, &mut commit.as_ref().to_vec()))) + } + fn setup_height(&self, bh: &BlockHeader) -> Result<(), Error> { self.db.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), bh)?; diff --git a/chain/src/types.rs b/chain/src/types.rs index 714e18da6..a077a662b 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -14,8 +14,10 @@ //! Base types that the block chain pipeline requires. +use secp::pedersen::Commitment; + use grin_store::Error; -use core::core::{Block, BlockHeader}; +use core::core::{Block, BlockHeader, Output}; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; use core::ser; @@ -116,6 +118,12 @@ pub trait ChainStore: Send + Sync { /// Gets the block header at the provided height fn get_header_by_height(&self, height: u64) -> Result; + /// Gets an output by its hash + fn get_output(&self, h: &Hash) -> Result; + + /// Checks whether an output commitment exists and returns the output hash + fn has_output_commit(&self, commit: &Commitment) -> Result; + /// Saves the provided block header at the corresponding height. Also check /// the consistency of the height chain in store by assuring previous /// headers