query_extras
This commit is contained in:
parent
96298299e3
commit
a509bffdc0
@ -10,9 +10,11 @@ authors = ["Ethcore <admin@ethcore.io>"]
|
|||||||
log = "0.3"
|
log = "0.3"
|
||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
ethcore-util = "0.1.0"
|
ethcore-util = "0.1.0"
|
||||||
evmjit = { path = "rust-evmjit", optional = true }
|
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
flate2 = "0.2"
|
flate2 = "0.2"
|
||||||
|
rocksdb = "0.2.1"
|
||||||
|
|
||||||
|
evmjit = { path = "rust-evmjit", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
jit = ["evmjit"]
|
jit = ["evmjit"]
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
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::hash::*;
|
||||||
use util::uint::*;
|
use util::uint::*;
|
||||||
use util::rlp::*;
|
use util::rlp::*;
|
||||||
@ -23,10 +26,12 @@ pub struct BlockChain {
|
|||||||
genesis_hash: H256,
|
genesis_hash: H256,
|
||||||
genesis_state: HashMap<Address, Account>,
|
genesis_state: HashMap<Address, Account>,
|
||||||
|
|
||||||
|
last_block_number: U256,
|
||||||
|
|
||||||
// extras
|
// extras
|
||||||
// TODO: is arc really needed here, since blockchain itself will be wrapped
|
blocks_details: Extras<H256, BlockDetails>,
|
||||||
// into `Arc`?
|
blocks_hashes: Extras<U256, H256>,
|
||||||
block_details: Arc<Mutex<HashMap<H256, BlockDetails>>>
|
extras_db: DB
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockChain {
|
impl BlockChain {
|
||||||
@ -35,19 +40,26 @@ impl BlockChain {
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate ethcore_util as util;
|
/// extern crate ethcore_util as util;
|
||||||
/// extern crate ethcore;
|
/// extern crate ethcore;
|
||||||
|
/// use std::env;
|
||||||
/// use std::str::FromStr;
|
/// use std::str::FromStr;
|
||||||
/// use ethcore::genesis::*;
|
/// use ethcore::genesis::*;
|
||||||
/// use ethcore::blockchain::*;
|
/// use ethcore::blockchain::*;
|
||||||
/// use util::hash::*;
|
/// use util::hash::*;
|
||||||
|
/// use util::uint::*;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
|
/// let mut dir = env::temp_dir();
|
||||||
|
/// dir.push(H32::random().hex());
|
||||||
|
///
|
||||||
/// let genesis = Genesis::new_frontier();
|
/// let genesis = Genesis::new_frontier();
|
||||||
/// let bc = BlockChain::new(genesis);
|
/// 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_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_block, genesis_state) = genesis.drain();
|
||||||
|
|
||||||
let genesis_header = Rlp::new(&genesis_block).at(0).raw().to_vec();
|
let genesis_header = Rlp::new(&genesis_block).at(0).raw().to_vec();
|
||||||
@ -60,19 +72,25 @@ impl BlockChain {
|
|||||||
children: vec![]
|
children: vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: also insert into backing db
|
let db = DB::open_default(path.to_str().unwrap()).unwrap();
|
||||||
let mut block_details = HashMap::new();
|
|
||||||
block_details.insert(genesis_hash.clone(), genesis_details);
|
|
||||||
|
|
||||||
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_block: genesis_block,
|
||||||
genesis_header: genesis_header,
|
genesis_header: genesis_header,
|
||||||
genesis_hash: genesis_hash,
|
genesis_hash: genesis_hash,
|
||||||
genesis_state: genesis_state,
|
genesis_state: genesis_state,
|
||||||
block_details: Arc::new(Mutex::new(block_details))
|
last_block_number: U256::from(0u8),
|
||||||
};
|
blocks_details: Extras::new(ExtrasIndex::BlockDetails),
|
||||||
|
blocks_hashes: Extras::new(ExtrasIndex::BlockHash),
|
||||||
bc
|
extras_db: db
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn genesis_hash(&self) -> &H256 {
|
pub fn genesis_hash(&self) -> &H256 {
|
||||||
@ -114,11 +132,62 @@ impl BlockChain {
|
|||||||
unimplemented!();
|
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
|
/// Returns true if the given block is known
|
||||||
/// (though not necessarily a part of the canon chain).
|
/// (though not necessarily a part of the canon chain).
|
||||||
pub fn is_known(&self, hash: &H256) -> bool {
|
pub fn is_known(&self, hash: &H256) -> bool {
|
||||||
return false;
|
// TODO: first do lookup in blocks_db for given hash
|
||||||
//unimplemented!()
|
|
||||||
// TODO: check is hash exist in hashes
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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::uint::*;
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::rlp::*;
|
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 struct BlockDetails {
|
||||||
pub number: U256,
|
pub number: U256,
|
||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate flate2;
|
extern crate flate2;
|
||||||
|
extern crate rocksdb;
|
||||||
|
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
#[cfg(feature = "jit" )]
|
#[cfg(feature = "jit" )]
|
||||||
|
Loading…
Reference in New Issue
Block a user