extras refactored

This commit is contained in:
debris 2015-12-17 01:54:24 +01:00
parent 3862d639bc
commit 2251c469b8
3 changed files with 167 additions and 95 deletions

View File

@ -5,6 +5,7 @@ use util::sha3::*;
use blockheader::*; use blockheader::*;
use state::*; use state::*;
use transaction::*; use transaction::*;
use extras::*;
/// view onto block rlp /// view onto block rlp
pub struct BlockView<'a> { pub struct BlockView<'a> {
@ -12,40 +13,73 @@ pub struct BlockView<'a> {
} }
impl<'a> BlockView<'a> { impl<'a> BlockView<'a> {
/// Creates new view onto block from raw bytes
pub fn new(bytes: &'a [u8]) -> BlockView<'a> { pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
BlockView { BlockView {
rlp: Rlp::new(bytes) rlp: Rlp::new(bytes)
} }
} }
/// Creates new view onto block from rlp
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> { pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
BlockView { BlockView {
rlp: rlp rlp: rlp
} }
} }
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp } /// Return reference to underlaying rlp
pub fn header(&self) -> Header { self.rlp.val_at(0) } pub fn rlp(&self) -> &Rlp<'a> {
&self.rlp
}
/// Create new Header object from header rlp
pub fn header(&self) -> Header {
self.rlp.val_at(0)
}
/// Create new header view obto block head rlp
pub fn header_view(&self) -> HeaderView<'a> { pub fn header_view(&self) -> HeaderView<'a> {
HeaderView::new_from_rlp(self.rlp.at(0)) HeaderView::new_from_rlp(self.rlp.at(0))
} }
/// Return List of transactions in given block
pub fn transactions(&self) -> Vec<Transaction> { pub fn transactions(&self) -> Vec<Transaction> {
self.rlp.val_at(1) self.rlp.val_at(1)
} }
/// Return transaction hashes
pub fn transaction_hashes(&self) -> Vec<H256> { pub fn transaction_hashes(&self) -> Vec<H256> {
self.rlp.at(1).iter().map(|rlp| rlp.raw().sha3()).collect() self.rlp.at(1).iter().map(|rlp| rlp.raw().sha3()).collect()
} }
/// Return list of uncles of given block
pub fn uncles(&self) -> Vec<Header> { pub fn uncles(&self) -> Vec<Header> {
self.rlp.val_at(2) self.rlp.val_at(2)
} }
/// Return list of uncle hashes of given block
pub fn uncle_hashes(&self) -> Vec<H256> { pub fn uncle_hashes(&self) -> Vec<H256> {
self.rlp.at(2).iter().map(|rlp| rlp.raw().sha3()).collect() self.rlp.at(2).iter().map(|rlp| rlp.raw().sha3()).collect()
} }
/// Return BlockDetaile object of given block
/// note* children is always an empty vector,
/// cause we can't deducate them from rlp.
pub fn block_details(&self) -> BlockDetails {
let header = self.header_view();
BlockDetails {
number: header.number(),
total_difficulty: header.difficulty(),
parent: header.parent_hash(),
children: vec![]
}
}
}
impl<'a> Hashable for BlockView<'a> {
fn sha3(&self) -> H256 {
self.header_view().sha3()
}
} }
/// Active model of a block within the blockchain /// Active model of a block within the blockchain

View File

@ -8,15 +8,11 @@ use util::hash::*;
use util::uint::*; use util::uint::*;
use util::rlp::*; use util::rlp::*;
use util::hashdb::*; use util::hashdb::*;
use util::overlaydb::*;
use util::sha3::*; use util::sha3::*;
use util::bytes::*; use util::bytes::*;
use util::squeeze::*; use util::squeeze::*;
use blockheader::*; use blockheader::*;
use block::*; use block::*;
use verifiedblock::*;
use importroute::*;
use account::*;
use genesis::*; use genesis::*;
use extras::*; use extras::*;
use transaction::*; use transaction::*;
@ -31,24 +27,17 @@ pub struct CacheSize {
} }
pub struct BlockChain { pub struct BlockChain {
// rlp list of 3
genesis_block: Bytes,
// genesis block header
_genesis_header: Bytes,
genesis_hash: H256,
_genesis_state: HashMap<Address, Account>,
last_block_number: Cell<U256>, last_block_number: Cell<U256>,
// block cache // block cache
blocks: RefCell<HashMap<H256, Bytes>>, blocks: RefCell<HashMap<H256, Bytes>>,
// extra caches // extra caches
block_details: Extras<H256, BlockDetails>, block_details: RefCell<HashMap<H256, BlockDetails>>,
block_hashes: Extras<U256, H256>, block_hashes: RefCell<HashMap<U256, H256>>,
transaction_addresses: Extras<H256, TransactionAddress>, transaction_addresses: RefCell<HashMap<H256, TransactionAddress>>,
block_logs: Extras<H256, BlockLogBlooms>, block_logs: RefCell<HashMap<H256, BlockLogBlooms>>,
blocks_blooms: Extras<H256, BlocksBlooms>, blocks_blooms: RefCell<HashMap<H256, BlocksBlooms>>,
extras_db: DB, extras_db: DB,
blocks_db: DB blocks_db: DB
@ -74,24 +63,15 @@ impl BlockChain {
/// let genesis = Genesis::new_frontier(); /// let genesis = Genesis::new_frontier();
/// let bc = BlockChain::new(genesis, &dir); /// let bc = BlockChain::new(genesis, &dir);
/// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; /// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3";
/// assert_eq!(bc.genesis_hash(), &H256::from_str(genesis_hash).unwrap()); /// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap());
/// assert!(bc.is_known(bc.genesis_hash())); /// assert!(bc.is_known(&bc.genesis_hash()));
/// assert_eq!(bc.genesis_hash(), &bc.block_hash(&U256::from(0u8)).unwrap()); /// assert_eq!(bc.genesis_hash(), bc.block_hash(&U256::from(0u8)).unwrap());
/// } /// }
/// ``` /// ```
pub fn new(genesis: Genesis, path: &Path) -> BlockChain { pub fn new(genesis: Genesis, path: &Path) -> BlockChain {
let (genesis_block, genesis_state) = genesis.drain(); let (genesis_block, _genesis_state) = genesis.drain();
let genesis_header = BlockView::new(&genesis_block).header_view().rlp().raw().to_vec();
let genesis_hash = HeaderView::new(&genesis_header).sha3();
let genesis_details = BlockDetails {
number: U256::from(0u64),
total_difficulty: HeaderView::new(&genesis_header).difficulty(),
parent: H256::new(),
children: vec![]
};
// open dbs
let mut extras_path = path.to_path_buf(); let mut extras_path = path.to_path_buf();
extras_path.push("extras"); extras_path.push("extras");
let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap(); let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap();
@ -100,34 +80,41 @@ impl BlockChain {
blocks_path.push("blocks"); blocks_path.push("blocks");
let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap(); let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap();
{ let bc = BlockChain {
let batch = WriteBatch::new();
batch.put(&genesis_hash.to_extras_slice(ExtrasIndex::BlockDetails), &encode(&genesis_details)).unwrap();
batch.put(&U256::from(0u8).to_extras_slice(ExtrasIndex::BlockHash), &encode(&genesis_hash)).unwrap();
extras_db.write(batch).unwrap();
blocks_db.put(&genesis_hash, &genesis_block).unwrap();
}
BlockChain {
genesis_block: genesis_block,
_genesis_header: genesis_header,
genesis_hash: genesis_hash,
_genesis_state: genesis_state,
last_block_number: Cell::new(U256::from(0u8)), last_block_number: Cell::new(U256::from(0u8)),
blocks: RefCell::new(HashMap::new()), blocks: RefCell::new(HashMap::new()),
block_details: Extras::new(ExtrasIndex::BlockDetails), block_details: RefCell::new(HashMap::new()),
block_hashes: Extras::new(ExtrasIndex::BlockHash), block_hashes: RefCell::new(HashMap::new()),
transaction_addresses: Extras::new(ExtrasIndex::TransactionAddress), transaction_addresses: RefCell::new(HashMap::new()),
block_logs: Extras::new(ExtrasIndex::BlockLogBlooms), block_logs: RefCell::new(HashMap::new()),
blocks_blooms: Extras::new(ExtrasIndex::BlocksBlooms), blocks_blooms: RefCell::new(HashMap::new()),
extras_db: extras_db, extras_db: extras_db,
blocks_db: blocks_db blocks_db: blocks_db
} };
bc.insert_block(&genesis_block);
bc
} }
pub fn import_block(&self, _block: &[u8], _db: &OverlayDB) -> ImportRoute { /// Inserts the block into backing cache database.
unimplemented!(); /// Expects the block to be valid and already verified.
/// If the block is already known, does nothing.
pub fn insert_block(&self, bytes: &[u8]) {
let block = BlockView::new(bytes);
let header = block.header_view();
if self.is_known(&header.sha3()) {
return;
}
let hash = block.sha3();
self.blocks_db.put(&hash, &bytes).unwrap();
let batch = WriteBatch::new();
batch.put_extras(&hash, &block.block_details());
batch.put_extras(&header.number(), &hash);
self.extras_db.write(batch).unwrap();
} }
/// Returns true if the given block is known /// Returns true if the given block is known
@ -143,8 +130,8 @@ impl BlockChain {
} }
/// Returns reference to genesis hash /// Returns reference to genesis hash
pub fn genesis_hash(&self) -> &H256 { pub fn genesis_hash(&self) -> H256 {
&self.genesis_hash self.block_hash(&U256::from(0u8)).expect("Genesis hash should always exist")
} }
/// Get the partial-header of a block /// Get the partial-header of a block
@ -224,8 +211,8 @@ impl BlockChain {
} }
} }
fn query_extras<K, T>(&self, hash: &K, cache: &Extras<K, T>) -> Option<T> where fn query_extras<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> Option<T> where
T: Clone + Decodable, T: Clone + Decodable + ExtrasIndexable,
K: ExtrasSliceConvertable + Eq + Hash + Clone { K: ExtrasSliceConvertable + Eq + Hash + Clone {
{ {
let read = cache.borrow(); let read = cache.borrow();
@ -235,22 +222,16 @@ impl BlockChain {
} }
} }
let opt = self.extras_db.get(&hash.to_extras_slice(cache.index())) self.extras_db.get_extras(hash).map(| t: T | {
.expect("Low level database error. Some issue with disk?"); let mut write = cache.borrow_mut();
write.insert(hash.clone(), t.clone());
match opt { t
Some(b) => { })
let t: T = decode(&b);
let mut write = cache.borrow_mut();
write.insert(hash.clone(), t.clone());
Some(t)
},
None => None
}
} }
fn query_extras_exist<K, T>(&self, hash: &K, cache: &Extras<K, T>) -> bool where fn query_extras_exist<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> bool where
K: ExtrasSliceConvertable + Eq + Hash + Clone { K: ExtrasSliceConvertable + Eq + Hash + Clone,
T: ExtrasIndexable {
{ {
let read = cache.borrow(); let read = cache.borrow();
match read.get(hash) { match read.get(hash) {
@ -259,10 +240,7 @@ impl BlockChain {
} }
} }
let opt = self.extras_db.get(&hash.to_extras_slice(cache.index())) self.extras_db.extras_exists::<_, T>(hash)
.expect("Low level database error. Some issue with disk?");
opt.is_some()
} }
/// Get current cache size /// Get current cache size

View File

@ -1,13 +1,10 @@
use std::collections::HashMap;
use std::cell::RefCell;
use std::ops::Deref;
use std::hash::Hash;
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use rocksdb::{DB, Writable};
use util::uint::*; use util::uint::*;
use util::hash::*; use util::hash::*;
use util::rlp::*; use util::rlp::*;
/// workaround for lack of integer templates in Rust /// Represents index of extra data in database
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ExtrasIndex { pub enum ExtrasIndex {
BlockDetails = 0, BlockDetails = 0,
@ -17,26 +14,51 @@ pub enum ExtrasIndex {
BlocksBlooms = 4 BlocksBlooms = 4
} }
/// rw locked extra data with slice suffix /// trait used to write Extras data to db
// consifer if arc needed here, since blockchain itself will be wrapped pub trait ExtrasWritable {
pub struct Extras<K, T>(RefCell<HashMap<K, T>>, ExtrasIndex) where K: Eq + Hash; fn put_extras<K, T>(&self, hash: &K, value: &T) where
T: ExtrasIndexable + Encodable,
impl<K, T> Extras<K, T> where K: Eq + Hash { K: ExtrasSliceConvertable;
pub fn new(i: ExtrasIndex) -> Extras<K, T> {
Extras(RefCell::new(HashMap::new()), i)
}
pub fn index(&self) -> ExtrasIndex { self.1 }
} }
impl<K, T> Deref for Extras<K, T> where K : Eq + Hash { /// trait used to read Extras data from db
type Target = RefCell<HashMap<K, T>>; pub trait ExtrasReadable {
fn get_extras<K, T>(&self, hash: &K) -> Option<T> where
T: ExtrasIndexable + Decodable,
K: ExtrasSliceConvertable;
fn deref(&self) -> &Self::Target { fn extras_exists<K, T>(&self, hash: &K) -> bool where
&self.0 T: ExtrasIndexable,
K: ExtrasSliceConvertable;
}
impl<W> ExtrasWritable for W where W: Writable {
fn put_extras<K, T>(&self, hash: &K, value: &T) where
T: ExtrasIndexable + Encodable,
K: ExtrasSliceConvertable {
self.put(&hash.to_extras_slice(T::extras_index()), &encode(value)).unwrap()
} }
} }
impl ExtrasReadable for DB {
fn get_extras<K, T>(&self, hash: &K) -> Option<T> where
T: ExtrasIndexable + Decodable,
K: ExtrasSliceConvertable {
self.get(&hash.to_extras_slice(T::extras_index())).unwrap()
.map(|v| decode(&v))
}
fn extras_exists<K, T>(&self, hash: &K) -> bool where
T: ExtrasIndexable,
K: ExtrasSliceConvertable {
self.get(&hash.to_extras_slice(T::extras_index())).unwrap().is_some()
}
}
/// Implementations should convert arbitrary type to database key slice
pub trait ExtrasSliceConvertable { pub trait ExtrasSliceConvertable {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264; fn to_extras_slice(&self, i: ExtrasIndex) -> H264;
} }
@ -55,7 +77,18 @@ impl ExtrasSliceConvertable for U256 {
} }
} }
/// Types implementing this trait can be indexed in extras database
pub trait ExtrasIndexable {
fn extras_index() -> ExtrasIndex;
}
impl ExtrasIndexable for H256 {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockHash
}
}
/// Familial details concerning a block
#[derive(Clone)] #[derive(Clone)]
pub struct BlockDetails { pub struct BlockDetails {
pub number: U256, pub number: U256,
@ -64,6 +97,12 @@ pub struct BlockDetails {
pub children: Vec<H256> pub children: Vec<H256>
} }
impl ExtrasIndexable for BlockDetails {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockDetails
}
}
impl HeapSizeOf for BlockDetails { impl HeapSizeOf for BlockDetails {
fn heap_size_of_children(&self) -> usize { fn heap_size_of_children(&self) -> usize {
self.children.heap_size_of_children() self.children.heap_size_of_children()
@ -94,11 +133,18 @@ impl Encodable for BlockDetails {
} }
} }
/// Log blooms of certain block
#[derive(Clone)] #[derive(Clone)]
pub struct BlockLogBlooms { pub struct BlockLogBlooms {
pub blooms: Vec<H2048> pub blooms: Vec<H2048>
} }
impl ExtrasIndexable for BlockLogBlooms {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlockLogBlooms
}
}
impl HeapSizeOf for BlockLogBlooms { impl HeapSizeOf for BlockLogBlooms {
fn heap_size_of_children(&self) -> usize { fn heap_size_of_children(&self) -> usize {
self.blooms.heap_size_of_children() self.blooms.heap_size_of_children()
@ -121,10 +167,17 @@ impl Encodable for BlockLogBlooms {
} }
} }
/// Neighboring log blooms on certain level
pub struct BlocksBlooms { pub struct BlocksBlooms {
pub blooms: [H2048; 16] pub blooms: [H2048; 16]
} }
impl ExtrasIndexable for BlocksBlooms {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::BlocksBlooms
}
}
impl HeapSizeOf for BlocksBlooms { impl HeapSizeOf for BlocksBlooms {
fn heap_size_of_children(&self) -> usize { 0 } fn heap_size_of_children(&self) -> usize { 0 }
} }
@ -160,12 +213,19 @@ impl Encodable for BlocksBlooms {
} }
} }
/// Represents address of certain transaction within block
#[derive(Clone)] #[derive(Clone)]
pub struct TransactionAddress { pub struct TransactionAddress {
pub block_hash: H256, pub block_hash: H256,
pub index: u64 pub index: u64
} }
impl ExtrasIndexable for TransactionAddress {
fn extras_index() -> ExtrasIndex {
ExtrasIndex::TransactionAddress
}
}
impl HeapSizeOf for TransactionAddress { impl HeapSizeOf for TransactionAddress {
fn heap_size_of_children(&self) -> usize { 0 } fn heap_size_of_children(&self) -> usize { 0 }
} }