From 7ee408e0679d076897189f66df0d1aed771ff039 Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Thu, 9 Feb 2017 11:41:46 -0800 Subject: [PATCH] Moved down to the store module some common persistence code. --- chain/src/pipe.rs | 13 +++++------ chain/src/store.rs | 57 ++++++---------------------------------------- chain/src/types.rs | 9 +------- store/Cargo.toml | 1 + store/src/lib.rs | 51 +++++++++++++++++++++++++++++++++-------- 5 files changed, 57 insertions(+), 74 deletions(-) diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index 5405f2d17..e2346e214 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -26,6 +26,7 @@ use core::core::target::Difficulty; use core::core::{BlockHeader, Block, Proof}; use core::pow; use core::ser; +use grin_store; use types; use types::{Tip, ChainStore, ChainAdapter, NoopAdapter}; use store; @@ -69,12 +70,12 @@ pub enum Error { /// Block height is invalid (not previous + 1) InvalidBlockHeight, /// Internal issue when trying to save or load data from store - StoreErr(types::Error), + StoreErr(grin_store::Error), SerErr(ser::Error), } -impl From for Error { - fn from(e: types::Error) -> Error { +impl From for Error { + fn from(e: grin_store::Error) -> Error { Error::StoreErr(e) } } @@ -222,7 +223,7 @@ fn validate_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> { /// Officially adds the block to our chain. fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> { - ctx.store.save_block(b).map_err(&Error::StoreErr); + ctx.store.save_block(b).map_err(&Error::StoreErr)?; // broadcast the block let adapter = ctx.adapter.clone(); @@ -232,9 +233,7 @@ fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> { /// Officially adds the block header to our header chain. fn add_block_header(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> { - ctx.store.save_block_header(bh).map_err(&Error::StoreErr); - - Ok(()) + ctx.store.save_block_header(bh).map_err(&Error::StoreErr) } /// Directly updates the head if we've just appended a new block to it or handle diff --git a/chain/src/store.rs b/chain/src/store.rs index 10f70b7c6..9448590c1 100644 --- a/chain/src/store.rs +++ b/chain/src/store.rs @@ -14,17 +14,13 @@ //! Implements storage primitives required by the chain -use byteorder::{WriteBytesExt, BigEndian}; - use types::*; use core::core::hash::{Hash, Hashed}; use core::core::{Block, BlockHeader}; -use grin_store; +use grin_store::{self, Error, to_key, u64_to_key, option_to_not_found}; const STORE_SUBPATH: &'static str = "chain"; -const SEP: u8 = ':' as u8; - const BLOCK_HEADER_PREFIX: u8 = 'h' as u8; const BLOCK_PREFIX: u8 = 'b' as u8; const HEAD_PREFIX: u8 = 'H' as u8; @@ -39,8 +35,7 @@ pub struct ChainKVStore { impl ChainKVStore { pub fn new(root_path: String) -> Result { - let db = try!(grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str()) - .map_err(to_store_err)); + let db = grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str())?; Ok(ChainKVStore { db: db }) } } @@ -61,7 +56,6 @@ impl ChainStore for ChainKVStore { .put_ser(&vec![HEAD_PREFIX], t)? .put_ser(&vec![HEADER_HEAD_PREFIX], t)? .write() - .map_err(&to_store_err) } fn get_header_head(&self) -> Result { @@ -69,7 +63,7 @@ impl ChainStore for ChainKVStore { } fn save_header_head(&self, t: &Tip) -> Result<(), Error> { - self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t).map_err(&to_store_err) + self.db.put_ser(&vec![HEADER_HEAD_PREFIX], t) } fn get_block(&self, h: &Hash) -> Result { @@ -87,14 +81,11 @@ impl ChainStore for ChainKVStore { .put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..], &b.header)? .write() - .map_err(&to_store_err) } fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> { - self.db - .put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..], - bh) - .map_err(&to_store_err) + self.db.put_ser( + &to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..], bh) } fn get_header_by_height(&self, height: u64) -> Result { @@ -102,7 +93,7 @@ impl ChainStore for ChainKVStore { } fn setup_height(&self, bh: &BlockHeader) -> Result<(), Error> { - self.db.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), bh).map_err(&to_store_err)?; + self.db.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, bh.height), bh)?; let mut prev_h = bh.previous; let mut prev_height = bh.height - 1; @@ -112,8 +103,7 @@ impl ChainStore for ChainKVStore { let real_prev = self.get_block_header(&prev_h)?; self.db .put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, real_prev.height), - &real_prev) - .map_err(&to_store_err)?; + &real_prev); prev_h = real_prev.previous; prev_height = real_prev.height - 1; } else { @@ -123,36 +113,3 @@ impl ChainStore for ChainKVStore { Ok(()) } } - -impl From for Error { - fn from(e: grin_store::Error) -> Error { - Error::StorageErr(e.to_string()) - } -} - -fn to_key(prefix: u8, val: &mut Vec) -> &mut Vec { - val.insert(0, SEP); - val.insert(0, prefix); - val -} - -fn u64_to_key<'a>(prefix: u8, val: u64) -> Vec { - let mut u64_vec = vec![]; - u64_vec.write_u64::(val).unwrap(); - u64_vec.insert(0, SEP); - u64_vec.insert(0, prefix); - u64_vec -} - -fn to_store_err(e: grin_store::Error) -> Error { - Error::StorageErr(format!("{:?}", e)) -} - -/// unwraps the inner option by converting the none case to a not found error -fn option_to_not_found(res: Result, grin_store::Error>) -> Result { - match res { - Ok(None) => Err(Error::NotFoundErr), - Ok(Some(o)) => Ok(o), - Err(e) => Err(to_store_err(e)), - } -} diff --git a/chain/src/types.rs b/chain/src/types.rs index fe7b48966..9f7f22cf0 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -14,6 +14,7 @@ //! Base types that the block chain pipeline requires. +use grin_store::Error; use core::core::{Block, BlockHeader}; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; @@ -82,14 +83,6 @@ impl ser::Readable for Tip { } } -#[derive(Debug)] -pub enum Error { - /// Couldn't find what we were looking for - NotFoundErr, - /// Error generated by the underlying storage layer - StorageErr(String), -} - /// Trait the chain pipeline requires an implementor for in order to process /// blocks. pub trait ChainStore: Send + Sync { diff --git a/store/Cargo.toml b/store/Cargo.toml index 86cf23c97..6479eaae0 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Ignotus Peverell "] [dependencies] +byteorder = "^0.5" rocksdb = "^0.6.0" tiny-keccak = "1.1" diff --git a/store/src/lib.rs b/store/src/lib.rs index df515f1b9..f21bf298e 100644 --- a/store/src/lib.rs +++ b/store/src/lib.rs @@ -20,30 +20,38 @@ #![deny(unused_mut)] #![warn(missing_docs)] +extern crate byteorder; extern crate grin_core as core; extern crate rocksdb; +const SEP: u8 = ':' as u8; + use std::fmt; use std::sync::RwLock; -use core::ser; - +use byteorder::{WriteBytesExt, BigEndian}; use rocksdb::{DB, WriteBatch, DBCompactionStyle}; +use core::ser; + /// Main error type for this crate. #[derive(Debug)] pub enum Error { + /// Couldn't find what we were looking for + NotFoundErr, /// Wraps an error originating from RocksDB (which unfortunately returns /// string errors). - RocksDbErr(rocksdb::Error), + RocksDbErr(String), /// Wraps a serialization error for Writeable or Readable SerErr(ser::Error), } + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Error::RocksDbErr(ref e) => write!(f, "RocksDb Error: {}", e.to_string()), + &Error::NotFoundErr => write!(f, "Not Found"), + &Error::RocksDbErr(ref s) => write!(f, "RocksDb Error: {}", s), &Error::SerErr(ref e) => write!(f, "Serialization Error: {}", e.to_string()), } } @@ -51,7 +59,7 @@ impl fmt::Display for Error { impl From for Error { fn from(e: rocksdb::Error) -> Error { - Error::RocksDbErr(e) + Error::RocksDbErr(e.to_string()) } } @@ -78,7 +86,7 @@ impl Store { /// Writes a single key/value pair to the db pub fn put(&self, key: &[u8], value: Vec) -> Result<(), Error> { let db = self.rdb.write().unwrap(); - db.put(key, &value[..]).map_err(Error::RocksDbErr) + db.put(key, &value[..]).map_err(&From::from) } /// Writes a single key and its `Writeable` value to the db. Encapsulates @@ -94,7 +102,7 @@ impl Store { /// Gets a value from the db, provided its key pub fn get(&self, key: &[u8]) -> Result>, Error> { let db = self.rdb.read().unwrap(); - db.get(key).map(|r| r.map(|o| o.to_vec())).map_err(Error::RocksDbErr) + db.get(key).map(|r| r.map(|o| o.to_vec())).map_err(From::from) } /// Gets a `Readable` value from the db, provided its key. Encapsulates @@ -124,7 +132,7 @@ impl Store { /// Deletes a key/value pair from the db pub fn delete(&self, key: &[u8]) -> Result<(), Error> { let db = self.rdb.write().unwrap(); - db.delete(key).map_err(Error::RocksDbErr) + db.delete(key).map_err(From::from) } /// Builds a new batch to be used with this store. @@ -137,7 +145,7 @@ impl Store { fn write(&self, batch: WriteBatch) -> Result<(), Error> { let db = self.rdb.write().unwrap(); - db.write(batch).map_err(Error::RocksDbErr) + db.write(batch).map_err(From::from) } } @@ -166,3 +174,28 @@ impl<'a> Batch<'a> { self.store.write(self.batch) } } + +/// Build a db key from a prefix and a byte vector identifier. +pub fn to_key(prefix: u8, id: &mut Vec) -> &mut Vec { + id.insert(0, SEP); + id.insert(0, prefix); + id +} + +/// Build a db key from a prefix and a numeric identifier. +pub fn u64_to_key<'a>(prefix: u8, val: u64) -> Vec { + let mut u64_vec = vec![]; + u64_vec.write_u64::(val).unwrap(); + u64_vec.insert(0, SEP); + u64_vec.insert(0, prefix); + u64_vec +} + +/// unwraps the inner option by converting the none case to a not found error +pub fn option_to_not_found(res: Result, Error>) -> Result { + match res { + Ok(None) => Err(Error::NotFoundErr), + Ok(Some(o)) => Ok(o), + Err(e) => Err(e), + } +}