From 4e36c63cbbee1b7d057df9f277cbfad9f41ef050 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Thu, 20 Apr 2017 11:26:53 -0700 Subject: [PATCH] Save outputs under their own keys Save outputs in every new block under their own hash. Done in the same batch as the block. Allows for direct output lookups by hash required by the p2p layer. Also store an index of output commitment to output hash for wallet and input lookups. --- chain/src/store.rs | 29 +++++++++++++++++++++++++---- chain/src/types.rs | 10 +++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) 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