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.
This commit is contained in:
Ignotus Peverell 2017-04-20 11:26:53 -07:00
parent ca496ee101
commit 4e36c63cbb
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
2 changed files with 34 additions and 5 deletions

View file

@ -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<Output, Error> {
option_to_not_found(self.db.get_ser(&to_key(OUTPUT_PREFIX, &mut h.to_vec())))
}
fn has_output_commit(&self, commit: &Commitment) -> Result<Hash, Error> {
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)?;

View file

@ -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<BlockHeader, Error>;
/// Gets an output by its hash
fn get_output(&self, h: &Hash) -> Result<Output, Error>;
/// Checks whether an output commitment exists and returns the output hash
fn has_output_commit(&self, commit: &Commitment) -> Result<Hash, Error>;
/// Saves the provided block header at the corresponding height. Also check
/// the consistency of the height chain in store by assuring previous
/// headers