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::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<types::Error> for Error {
fn from(e: types::Error) -> Error {
impl From<grin_store::Error> 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

View file

@ -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<ChainKVStore, Error> {
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<Tip, Error> {
@ -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<Block, Error> {
@ -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<BlockHeader, Error> {
@ -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<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.
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<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
/// blocks.
pub trait ChainStore: Send + Sync {

View file

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

View file

@ -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<rocksdb::Error> 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<u8>) -> 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<Option<Vec<u8>>, 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<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),
}
}