query_extras

This commit is contained in:
debris 2015-12-13 22:39:01 +01:00
parent 96298299e3
commit a509bffdc0
4 changed files with 141 additions and 18 deletions

View File

@ -10,9 +10,11 @@ authors = ["Ethcore <admin@ethcore.io>"]
log = "0.3"
env_logger = "0.3"
ethcore-util = "0.1.0"
evmjit = { path = "rust-evmjit", optional = true }
rustc-serialize = "0.3"
flate2 = "0.2"
rocksdb = "0.2.1"
evmjit = { path = "rust-evmjit", optional = true }
[features]
jit = ["evmjit"]

View File

@ -1,5 +1,8 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
use std::path::Path;
use std::hash::Hash;
use rocksdb::{DB, WriteBatch, Writable};
use util::hash::*;
use util::uint::*;
use util::rlp::*;
@ -23,10 +26,12 @@ pub struct BlockChain {
genesis_hash: H256,
genesis_state: HashMap<Address, Account>,
last_block_number: U256,
// extras
// TODO: is arc really needed here, since blockchain itself will be wrapped
// into `Arc`?
block_details: Arc<Mutex<HashMap<H256, BlockDetails>>>
blocks_details: Extras<H256, BlockDetails>,
blocks_hashes: Extras<U256, H256>,
extras_db: DB
}
impl BlockChain {
@ -35,19 +40,26 @@ impl BlockChain {
/// ```rust
/// extern crate ethcore_util as util;
/// extern crate ethcore;
/// use std::env;
/// use std::str::FromStr;
/// use ethcore::genesis::*;
/// use ethcore::blockchain::*;
/// use util::hash::*;
/// use util::uint::*;
///
/// fn main() {
/// let mut dir = env::temp_dir();
/// dir.push(H32::random().hex());
///
/// let genesis = Genesis::new_frontier();
/// let bc = BlockChain::new(genesis);
/// 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.number_hash(&U256::from(0u8)).unwrap());
/// }
/// ```
pub fn new(genesis: Genesis) -> BlockChain {
pub fn new(genesis: Genesis, path: &Path) -> BlockChain {
let (genesis_block, genesis_state) = genesis.drain();
let genesis_header = Rlp::new(&genesis_block).at(0).raw().to_vec();
@ -60,19 +72,25 @@ impl BlockChain {
children: vec![]
};
// TODO: also insert into backing db
let mut block_details = HashMap::new();
block_details.insert(genesis_hash.clone(), genesis_details);
let db = DB::open_default(path.to_str().unwrap()).unwrap();
let bc = BlockChain {
{
let mut batch = WriteBatch::new();
batch.put(&genesis_hash.to_extras_slice(ExtrasIndex::BlockDetails), &encode(&genesis_details));
batch.put(&U256::from(0u8).to_extras_slice(ExtrasIndex::BlockHash), &encode(&genesis_hash));
db.write(batch);
}
BlockChain {
genesis_block: genesis_block,
genesis_header: genesis_header,
genesis_hash: genesis_hash,
genesis_state: genesis_state,
block_details: Arc::new(Mutex::new(block_details))
};
bc
last_block_number: U256::from(0u8),
blocks_details: Extras::new(ExtrasIndex::BlockDetails),
blocks_hashes: Extras::new(ExtrasIndex::BlockHash),
extras_db: db
}
}
pub fn genesis_hash(&self) -> &H256 {
@ -114,11 +132,62 @@ impl BlockChain {
unimplemented!();
}
/// Get the hash of given block's number
pub fn number_hash(&self, hash: &U256) -> Option<H256> {
self.query_extras(hash, &self.blocks_hashes)
}
/// Returns true if the given block is known
/// (though not necessarily a part of the canon chain).
pub fn is_known(&self, hash: &H256) -> bool {
return false;
//unimplemented!()
// TODO: check is hash exist in hashes
// TODO: first do lookup in blocks_db for given hash
// TODO: consider taking into account current block
match self.query_extras(hash, &self.blocks_details) {
None => false,
Some(details) => details.number <= self.last_block_number
}
}
pub fn query_extras<K, T>(&self, hash: &K, cache: &Extras<K, T>) -> Option<T> where
T: Clone + Decodable,
K: ExtrasSliceConvertable + Eq + Hash + Clone {
{
let read = cache.read().unwrap();
match read.get(hash) {
Some(v) => return Some(v.clone()),
None => ()
}
}
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);
let mut write = cache.write().unwrap();
write.insert(hash.clone(), t.clone());
Some(t)
},
None => None
}
}
pub fn query_extras_exist<K, T>(&self, hash: &K, cache: &Extras<K, T>) -> bool where
K: ExtrasSliceConvertable + Eq + Hash + Clone {
{
let read = cache.read().unwrap();
match read.get(hash) {
Some(_) => return true,
None => ()
}
}
let opt = self.extras_db.get(&hash.to_extras_slice(cache.index()))
.expect("Low level database error. Some issue with disk?");
opt.is_some()
}
}

View File

@ -1,7 +1,58 @@
use std::collections::HashMap;
use std::sync::RwLock;
use std::ops::Deref;
use std::hash::Hash;
use util::uint::*;
use util::hash::*;
use util::rlp::*;
/// workaround for lack of integer templates in Rust
#[derive(Copy, Clone)]
pub enum ExtrasIndex {
BlockDetails = 0,
BlockHash = 1,
}
/// rw locked extra data with slice suffix
// consifer if arc needed here, since blockchain itself will be wrapped
pub struct Extras<K, T>(RwLock<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(RwLock::new(HashMap::new()), i)
}
pub fn index(&self) -> ExtrasIndex { self.1 }
}
impl<K, T> Deref for Extras<K, T> where K : Eq + Hash {
type Target = RwLock<HashMap<K, T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub trait ExtrasSliceConvertable {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264;
}
impl ExtrasSliceConvertable for H256 {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264 {
let mut slice = H264::from_slice(self);
slice[32] = i as u8;
slice
}
}
impl ExtrasSliceConvertable for U256 {
fn to_extras_slice(&self, i: ExtrasIndex) -> H264 {
H256::from(self).to_extras_slice(i)
}
}
#[derive(Clone)]
pub struct BlockDetails {
pub number: U256,
pub total_difficulty: U256,

View File

@ -73,6 +73,7 @@
extern crate log;
extern crate rustc_serialize;
extern crate flate2;
extern crate rocksdb;
extern crate env_logger;
#[cfg(feature = "jit" )]