mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Moved down to the store module some common persistence code.
This commit is contained in:
parent
1c2b70f78f
commit
7ee408e067
5 changed files with 57 additions and 74 deletions
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue