Moved down to the store module some common persistence code.

This commit is contained in:
Ignotus Peverell 2017-02-09 11:41:46 -08:00
parent 1c2b70f78f
commit 7ee408e067
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
5 changed files with 57 additions and 74 deletions

View file

@ -26,6 +26,7 @@ use core::core::target::Difficulty;
use core::core::{BlockHeader, Block, Proof}; use core::core::{BlockHeader, Block, Proof};
use core::pow; use core::pow;
use core::ser; use core::ser;
use grin_store;
use types; use types;
use types::{Tip, ChainStore, ChainAdapter, NoopAdapter}; use types::{Tip, ChainStore, ChainAdapter, NoopAdapter};
use store; use store;
@ -69,12 +70,12 @@ pub enum Error {
/// Block height is invalid (not previous + 1) /// Block height is invalid (not previous + 1)
InvalidBlockHeight, InvalidBlockHeight,
/// Internal issue when trying to save or load data from store /// Internal issue when trying to save or load data from store
StoreErr(types::Error), StoreErr(grin_store::Error),
SerErr(ser::Error), SerErr(ser::Error),
} }
impl From<types::Error> for Error { impl From<grin_store::Error> for Error {
fn from(e: types::Error) -> Error { fn from(e: grin_store::Error) -> Error {
Error::StoreErr(e) Error::StoreErr(e)
} }
} }
@ -222,7 +223,7 @@ fn validate_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
/// Officially adds the block to our chain. /// Officially adds the block to our chain.
fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> { 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 // broadcast the block
let adapter = ctx.adapter.clone(); 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. /// Officially adds the block header to our header chain.
fn add_block_header(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> { fn add_block_header(bh: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> {
ctx.store.save_block_header(bh).map_err(&Error::StoreErr); ctx.store.save_block_header(bh).map_err(&Error::StoreErr)
Ok(())
} }
/// Directly updates the head if we've just appended a new block to it or handle /// Directly updates the head if we've just appended a new block to it or handle

View file

@ -14,17 +14,13 @@
//! Implements storage primitives required by the chain //! Implements storage primitives required by the chain
use byteorder::{WriteBytesExt, BigEndian};
use types::*; use types::*;
use core::core::hash::{Hash, Hashed}; use core::core::hash::{Hash, Hashed};
use core::core::{Block, BlockHeader}; 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 STORE_SUBPATH: &'static str = "chain";
const SEP: u8 = ':' as u8;
const BLOCK_HEADER_PREFIX: u8 = 'h' as u8; const BLOCK_HEADER_PREFIX: u8 = 'h' as u8;
const BLOCK_PREFIX: u8 = 'b' as u8; const BLOCK_PREFIX: u8 = 'b' as u8;
const HEAD_PREFIX: u8 = 'H' as u8; const HEAD_PREFIX: u8 = 'H' as u8;
@ -39,8 +35,7 @@ pub struct ChainKVStore {
impl ChainKVStore { impl ChainKVStore {
pub fn new(root_path: String) -> Result<ChainKVStore, Error> { pub fn new(root_path: String) -> Result<ChainKVStore, Error> {
let db = try!(grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str()) let db = grin_store::Store::open(format!("{}/{}", root_path, STORE_SUBPATH).as_str())?;
.map_err(to_store_err));
Ok(ChainKVStore { db: db }) Ok(ChainKVStore { db: db })
} }
} }
@ -61,7 +56,6 @@ impl ChainStore for ChainKVStore {
.put_ser(&vec![HEAD_PREFIX], t)? .put_ser(&vec![HEAD_PREFIX], t)?
.put_ser(&vec![HEADER_HEAD_PREFIX], t)? .put_ser(&vec![HEADER_HEAD_PREFIX], t)?
.write() .write()
.map_err(&to_store_err)
} }
fn get_header_head(&self) -> Result<Tip, Error> { fn get_header_head(&self) -> Result<Tip, Error> {
@ -69,7 +63,7 @@ impl ChainStore for ChainKVStore {
} }
fn save_header_head(&self, t: &Tip) -> Result<(), Error> { 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<Block, Error> { fn get_block(&self, h: &Hash) -> Result<Block, Error> {
@ -87,14 +81,11 @@ impl ChainStore for ChainKVStore {
.put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..], .put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut b.hash().to_vec())[..],
&b.header)? &b.header)?
.write() .write()
.map_err(&to_store_err)
} }
fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> { fn save_block_header(&self, bh: &BlockHeader) -> Result<(), Error> {
self.db self.db.put_ser(
.put_ser(&to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..], &to_key(BLOCK_HEADER_PREFIX, &mut bh.hash().to_vec())[..], bh)
bh)
.map_err(&to_store_err)
} }
fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> { fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> {
@ -102,7 +93,7 @@ impl ChainStore for ChainKVStore {
} }
fn setup_height(&self, bh: &BlockHeader) -> Result<(), Error> { 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_h = bh.previous;
let mut prev_height = bh.height - 1; let mut prev_height = bh.height - 1;
@ -112,8 +103,7 @@ impl ChainStore for ChainKVStore {
let real_prev = self.get_block_header(&prev_h)?; let real_prev = self.get_block_header(&prev_h)?;
self.db self.db
.put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, real_prev.height), .put_ser(&u64_to_key(HEADER_HEIGHT_PREFIX, real_prev.height),
&real_prev) &real_prev);
.map_err(&to_store_err)?;
prev_h = real_prev.previous; prev_h = real_prev.previous;
prev_height = real_prev.height - 1; prev_height = real_prev.height - 1;
} else { } else {
@ -123,36 +113,3 @@ impl ChainStore for ChainKVStore {
Ok(()) Ok(())
} }
} }
impl From<grin_store::Error> for Error {
fn from(e: grin_store::Error) -> Error {
Error::StorageErr(e.to_string())
}
}
fn to_key(prefix: u8, val: &mut Vec<u8>) -> &mut Vec<u8> {
val.insert(0, SEP);
val.insert(0, prefix);
val
}
fn u64_to_key<'a>(prefix: u8, val: u64) -> Vec<u8> {
let mut u64_vec = vec![];
u64_vec.write_u64::<BigEndian>(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<T>(res: Result<Option<T>, grin_store::Error>) -> Result<T, Error> {
match res {
Ok(None) => Err(Error::NotFoundErr),
Ok(Some(o)) => Ok(o),
Err(e) => Err(to_store_err(e)),
}
}

View file

@ -14,6 +14,7 @@
//! Base types that the block chain pipeline requires. //! Base types that the block chain pipeline requires.
use grin_store::Error;
use core::core::{Block, BlockHeader}; use core::core::{Block, BlockHeader};
use core::core::hash::{Hash, Hashed}; use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty; use core::core::target::Difficulty;
@ -82,14 +83,6 @@ impl ser::Readable<Tip> 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 /// Trait the chain pipeline requires an implementor for in order to process
/// blocks. /// blocks.
pub trait ChainStore: Send + Sync { pub trait ChainStore: Send + Sync {

View file

@ -4,6 +4,7 @@ version = "0.1.0"
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"] authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
[dependencies] [dependencies]
byteorder = "^0.5"
rocksdb = "^0.6.0" rocksdb = "^0.6.0"
tiny-keccak = "1.1" tiny-keccak = "1.1"

View file

@ -20,30 +20,38 @@
#![deny(unused_mut)] #![deny(unused_mut)]
#![warn(missing_docs)] #![warn(missing_docs)]
extern crate byteorder;
extern crate grin_core as core; extern crate grin_core as core;
extern crate rocksdb; extern crate rocksdb;
const SEP: u8 = ':' as u8;
use std::fmt; use std::fmt;
use std::sync::RwLock; use std::sync::RwLock;
use core::ser; use byteorder::{WriteBytesExt, BigEndian};
use rocksdb::{DB, WriteBatch, DBCompactionStyle}; use rocksdb::{DB, WriteBatch, DBCompactionStyle};
use core::ser;
/// Main error type for this crate. /// Main error type for this crate.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Couldn't find what we were looking for
NotFoundErr,
/// Wraps an error originating from RocksDB (which unfortunately returns /// Wraps an error originating from RocksDB (which unfortunately returns
/// string errors). /// string errors).
RocksDbErr(rocksdb::Error), RocksDbErr(String),
/// Wraps a serialization error for Writeable or Readable /// Wraps a serialization error for Writeable or Readable
SerErr(ser::Error), SerErr(ser::Error),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { 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()), &Error::SerErr(ref e) => write!(f, "Serialization Error: {}", e.to_string()),
} }
} }
@ -51,7 +59,7 @@ impl fmt::Display for Error {
impl From<rocksdb::Error> for Error { impl From<rocksdb::Error> for Error {
fn from(e: rocksdb::Error) -> 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 /// Writes a single key/value pair to the db
pub fn put(&self, key: &[u8], value: Vec<u8>) -> Result<(), Error> { pub fn put(&self, key: &[u8], value: Vec<u8>) -> Result<(), Error> {
let db = self.rdb.write().unwrap(); 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 /// 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 /// Gets a value from the db, provided its key
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> { pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
let db = self.rdb.read().unwrap(); 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 /// 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 /// Deletes a key/value pair from the db
pub fn delete(&self, key: &[u8]) -> Result<(), Error> { pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
let db = self.rdb.write().unwrap(); 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. /// Builds a new batch to be used with this store.
@ -137,7 +145,7 @@ impl Store {
fn write(&self, batch: WriteBatch) -> Result<(), Error> { fn write(&self, batch: WriteBatch) -> Result<(), Error> {
let db = self.rdb.write().unwrap(); 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) 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<u8>) -> &mut Vec<u8> {
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<u8> {
let mut u64_vec = vec![];
u64_vec.write_u64::<BigEndian>(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<T>(res: Result<Option<T>, Error>) -> Result<T, Error> {
match res {
Ok(None) => Err(Error::NotFoundErr),
Ok(Some(o)) => Ok(o),
Err(e) => Err(e),
}
}