extras refactored
This commit is contained in:
parent
3862d639bc
commit
2251c469b8
38
src/block.rs
38
src/block.rs
@ -5,6 +5,7 @@ use util::sha3::*;
|
||||
use blockheader::*;
|
||||
use state::*;
|
||||
use transaction::*;
|
||||
use extras::*;
|
||||
|
||||
/// view onto block rlp
|
||||
pub struct BlockView<'a> {
|
||||
@ -12,40 +13,73 @@ pub struct BlockView<'a> {
|
||||
}
|
||||
|
||||
impl<'a> BlockView<'a> {
|
||||
/// Creates new view onto block from raw bytes
|
||||
pub fn new(bytes: &'a [u8]) -> BlockView<'a> {
|
||||
BlockView {
|
||||
rlp: Rlp::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new view onto block from rlp
|
||||
pub fn new_from_rlp(rlp: Rlp<'a>) -> BlockView<'a> {
|
||||
BlockView {
|
||||
rlp: rlp
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rlp(&self) -> &Rlp<'a> { &self.rlp }
|
||||
pub fn header(&self) -> Header { self.rlp.val_at(0) }
|
||||
/// Return reference to underlaying rlp
|
||||
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> {
|
||||
HeaderView::new_from_rlp(self.rlp.at(0))
|
||||
}
|
||||
|
||||
/// Return List of transactions in given block
|
||||
pub fn transactions(&self) -> Vec<Transaction> {
|
||||
self.rlp.val_at(1)
|
||||
}
|
||||
|
||||
/// Return transaction hashes
|
||||
pub fn transaction_hashes(&self) -> Vec<H256> {
|
||||
self.rlp.at(1).iter().map(|rlp| rlp.raw().sha3()).collect()
|
||||
}
|
||||
|
||||
/// Return list of uncles of given block
|
||||
pub fn uncles(&self) -> Vec<Header> {
|
||||
self.rlp.val_at(2)
|
||||
}
|
||||
|
||||
/// Return list of uncle hashes of given block
|
||||
pub fn uncle_hashes(&self) -> Vec<H256> {
|
||||
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
|
||||
|
@ -8,15 +8,11 @@ use util::hash::*;
|
||||
use util::uint::*;
|
||||
use util::rlp::*;
|
||||
use util::hashdb::*;
|
||||
use util::overlaydb::*;
|
||||
use util::sha3::*;
|
||||
use util::bytes::*;
|
||||
use util::squeeze::*;
|
||||
use blockheader::*;
|
||||
use block::*;
|
||||
use verifiedblock::*;
|
||||
use importroute::*;
|
||||
use account::*;
|
||||
use genesis::*;
|
||||
use extras::*;
|
||||
use transaction::*;
|
||||
@ -31,24 +27,17 @@ pub struct CacheSize {
|
||||
}
|
||||
|
||||
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>,
|
||||
|
||||
// block cache
|
||||
blocks: RefCell<HashMap<H256, Bytes>>,
|
||||
|
||||
// extra caches
|
||||
block_details: Extras<H256, BlockDetails>,
|
||||
block_hashes: Extras<U256, H256>,
|
||||
transaction_addresses: Extras<H256, TransactionAddress>,
|
||||
block_logs: Extras<H256, BlockLogBlooms>,
|
||||
blocks_blooms: Extras<H256, BlocksBlooms>,
|
||||
block_details: RefCell<HashMap<H256, BlockDetails>>,
|
||||
block_hashes: RefCell<HashMap<U256, H256>>,
|
||||
transaction_addresses: RefCell<HashMap<H256, TransactionAddress>>,
|
||||
block_logs: RefCell<HashMap<H256, BlockLogBlooms>>,
|
||||
blocks_blooms: RefCell<HashMap<H256, BlocksBlooms>>,
|
||||
|
||||
extras_db: DB,
|
||||
blocks_db: DB
|
||||
@ -74,24 +63,15 @@ impl BlockChain {
|
||||
/// let genesis = Genesis::new_frontier();
|
||||
/// let bc = BlockChain::new(genesis, &dir);
|
||||
/// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3";
|
||||
/// assert_eq!(bc.genesis_hash(), &H256::from_str(genesis_hash).unwrap());
|
||||
/// assert!(bc.is_known(bc.genesis_hash()));
|
||||
/// assert_eq!(bc.genesis_hash(), &bc.block_hash(&U256::from(0u8)).unwrap());
|
||||
/// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap());
|
||||
/// assert!(bc.is_known(&bc.genesis_hash()));
|
||||
/// assert_eq!(bc.genesis_hash(), bc.block_hash(&U256::from(0u8)).unwrap());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new(genesis: Genesis, path: &Path) -> BlockChain {
|
||||
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![]
|
||||
};
|
||||
let (genesis_block, _genesis_state) = genesis.drain();
|
||||
|
||||
// open dbs
|
||||
let mut extras_path = path.to_path_buf();
|
||||
extras_path.push("extras");
|
||||
let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap();
|
||||
@ -100,34 +80,41 @@ impl BlockChain {
|
||||
blocks_path.push("blocks");
|
||||
let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap();
|
||||
|
||||
{
|
||||
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,
|
||||
let bc = BlockChain {
|
||||
last_block_number: Cell::new(U256::from(0u8)),
|
||||
blocks: RefCell::new(HashMap::new()),
|
||||
block_details: Extras::new(ExtrasIndex::BlockDetails),
|
||||
block_hashes: Extras::new(ExtrasIndex::BlockHash),
|
||||
transaction_addresses: Extras::new(ExtrasIndex::TransactionAddress),
|
||||
block_logs: Extras::new(ExtrasIndex::BlockLogBlooms),
|
||||
blocks_blooms: Extras::new(ExtrasIndex::BlocksBlooms),
|
||||
block_details: RefCell::new(HashMap::new()),
|
||||
block_hashes: RefCell::new(HashMap::new()),
|
||||
transaction_addresses: RefCell::new(HashMap::new()),
|
||||
block_logs: RefCell::new(HashMap::new()),
|
||||
blocks_blooms: RefCell::new(HashMap::new()),
|
||||
extras_db: extras_db,
|
||||
blocks_db: blocks_db
|
||||
}
|
||||
};
|
||||
|
||||
bc.insert_block(&genesis_block);
|
||||
bc
|
||||
}
|
||||
|
||||
pub fn import_block(&self, _block: &[u8], _db: &OverlayDB) -> ImportRoute {
|
||||
unimplemented!();
|
||||
/// Inserts the block into backing cache database.
|
||||
/// 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
|
||||
@ -143,8 +130,8 @@ impl BlockChain {
|
||||
}
|
||||
|
||||
/// Returns reference to genesis hash
|
||||
pub fn genesis_hash(&self) -> &H256 {
|
||||
&self.genesis_hash
|
||||
pub fn genesis_hash(&self) -> H256 {
|
||||
self.block_hash(&U256::from(0u8)).expect("Genesis hash should always exist")
|
||||
}
|
||||
|
||||
/// 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
|
||||
T: Clone + Decodable,
|
||||
fn query_extras<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> Option<T> where
|
||||
T: Clone + Decodable + ExtrasIndexable,
|
||||
K: ExtrasSliceConvertable + Eq + Hash + Clone {
|
||||
{
|
||||
let read = cache.borrow();
|
||||
@ -235,22 +222,16 @@ impl BlockChain {
|
||||
}
|
||||
}
|
||||
|
||||
let opt = self.extras_db.get(&hash.to_extras_slice(cache.index()))
|
||||
.expect("Low level database error. Some issue with disk?");
|
||||
|
||||
match opt {
|
||||
Some(b) => {
|
||||
let t: T = decode(&b);
|
||||
self.extras_db.get_extras(hash).map(| t: T | {
|
||||
let mut write = cache.borrow_mut();
|
||||
write.insert(hash.clone(), t.clone());
|
||||
Some(t)
|
||||
},
|
||||
None => None
|
||||
}
|
||||
t
|
||||
})
|
||||
}
|
||||
|
||||
fn query_extras_exist<K, T>(&self, hash: &K, cache: &Extras<K, T>) -> bool where
|
||||
K: ExtrasSliceConvertable + Eq + Hash + Clone {
|
||||
fn query_extras_exist<K, T>(&self, hash: &K, cache: &RefCell<HashMap<K, T>>) -> bool where
|
||||
K: ExtrasSliceConvertable + Eq + Hash + Clone,
|
||||
T: ExtrasIndexable {
|
||||
{
|
||||
let read = cache.borrow();
|
||||
match read.get(hash) {
|
||||
@ -259,10 +240,7 @@ impl BlockChain {
|
||||
}
|
||||
}
|
||||
|
||||
let opt = self.extras_db.get(&hash.to_extras_slice(cache.index()))
|
||||
.expect("Low level database error. Some issue with disk?");
|
||||
|
||||
opt.is_some()
|
||||
self.extras_db.extras_exists::<_, T>(hash)
|
||||
}
|
||||
|
||||
/// Get current cache size
|
||||
|
@ -1,13 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::ops::Deref;
|
||||
use std::hash::Hash;
|
||||
use heapsize::HeapSizeOf;
|
||||
use rocksdb::{DB, Writable};
|
||||
use util::uint::*;
|
||||
use util::hash::*;
|
||||
use util::rlp::*;
|
||||
|
||||
/// workaround for lack of integer templates in Rust
|
||||
/// Represents index of extra data in database
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ExtrasIndex {
|
||||
BlockDetails = 0,
|
||||
@ -17,26 +14,51 @@ pub enum ExtrasIndex {
|
||||
BlocksBlooms = 4
|
||||
}
|
||||
|
||||
/// rw locked extra data with slice suffix
|
||||
// consifer if arc needed here, since blockchain itself will be wrapped
|
||||
pub struct Extras<K, T>(RefCell<HashMap<K, T>>, ExtrasIndex) where K: Eq + Hash;
|
||||
|
||||
impl<K, T> Extras<K, T> where K: Eq + Hash {
|
||||
pub fn new(i: ExtrasIndex) -> Extras<K, T> {
|
||||
Extras(RefCell::new(HashMap::new()), i)
|
||||
/// trait used to write Extras data to db
|
||||
pub trait ExtrasWritable {
|
||||
fn put_extras<K, T>(&self, hash: &K, value: &T) where
|
||||
T: ExtrasIndexable + Encodable,
|
||||
K: ExtrasSliceConvertable;
|
||||
}
|
||||
|
||||
pub fn index(&self) -> ExtrasIndex { self.1 }
|
||||
/// trait used to read Extras data from db
|
||||
pub trait ExtrasReadable {
|
||||
fn get_extras<K, T>(&self, hash: &K) -> Option<T> where
|
||||
T: ExtrasIndexable + Decodable,
|
||||
K: ExtrasSliceConvertable;
|
||||
|
||||
fn extras_exists<K, T>(&self, hash: &K) -> bool where
|
||||
T: ExtrasIndexable,
|
||||
K: ExtrasSliceConvertable;
|
||||
}
|
||||
|
||||
impl<K, T> Deref for Extras<K, T> where K : Eq + Hash {
|
||||
type Target = RefCell<HashMap<K, T>>;
|
||||
impl<W> ExtrasWritable for W where W: Writable {
|
||||
fn put_extras<K, T>(&self, hash: &K, value: &T) where
|
||||
T: ExtrasIndexable + Encodable,
|
||||
K: ExtrasSliceConvertable {
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
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 {
|
||||
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)]
|
||||
pub struct BlockDetails {
|
||||
pub number: U256,
|
||||
@ -64,6 +97,12 @@ pub struct BlockDetails {
|
||||
pub children: Vec<H256>
|
||||
}
|
||||
|
||||
impl ExtrasIndexable for BlockDetails {
|
||||
fn extras_index() -> ExtrasIndex {
|
||||
ExtrasIndex::BlockDetails
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for BlockDetails {
|
||||
fn heap_size_of_children(&self) -> usize {
|
||||
self.children.heap_size_of_children()
|
||||
@ -94,11 +133,18 @@ impl Encodable for BlockDetails {
|
||||
}
|
||||
}
|
||||
|
||||
/// Log blooms of certain block
|
||||
#[derive(Clone)]
|
||||
pub struct BlockLogBlooms {
|
||||
pub blooms: Vec<H2048>
|
||||
}
|
||||
|
||||
impl ExtrasIndexable for BlockLogBlooms {
|
||||
fn extras_index() -> ExtrasIndex {
|
||||
ExtrasIndex::BlockLogBlooms
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for BlockLogBlooms {
|
||||
fn heap_size_of_children(&self) -> usize {
|
||||
self.blooms.heap_size_of_children()
|
||||
@ -121,10 +167,17 @@ impl Encodable for BlockLogBlooms {
|
||||
}
|
||||
}
|
||||
|
||||
/// Neighboring log blooms on certain level
|
||||
pub struct BlocksBlooms {
|
||||
pub blooms: [H2048; 16]
|
||||
}
|
||||
|
||||
impl ExtrasIndexable for BlocksBlooms {
|
||||
fn extras_index() -> ExtrasIndex {
|
||||
ExtrasIndex::BlocksBlooms
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for BlocksBlooms {
|
||||
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)]
|
||||
pub struct TransactionAddress {
|
||||
pub block_hash: H256,
|
||||
pub index: u64
|
||||
}
|
||||
|
||||
impl ExtrasIndexable for TransactionAddress {
|
||||
fn extras_index() -> ExtrasIndex {
|
||||
ExtrasIndex::TransactionAddress
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for TransactionAddress {
|
||||
fn heap_size_of_children(&self) -> usize { 0 }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user