Merge remote-tracking branch 'origin/master'

This commit is contained in:
Gav Wood 2016-05-21 14:49:09 +02:00
commit 399dfc4c2e
47 changed files with 1565 additions and 1093 deletions

8
Cargo.lock generated
View File

@ -332,7 +332,7 @@ dependencies = [
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb 0.4.3 (git+https://github.com/arkpar/rust-rocksdb.git)", "rocksdb 0.4.3 (git+https://github.com/ethcore/rust-rocksdb)",
"rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -628,7 +628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "librocksdb-sys" name = "librocksdb-sys"
version = "0.2.3" version = "0.2.3"
source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1"
dependencies = [ dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -970,10 +970,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rocksdb" name = "rocksdb"
version = "0.4.3" version = "0.4.3"
source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1"
dependencies = [ dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)", "librocksdb-sys 0.2.3 (git+https://github.com/ethcore/rust-rocksdb)",
] ]
[[package]] [[package]]

24
db/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
description = "Ethcore Database"
homepage = "http://ethcore.io"
license = "GPL-3.0"
name = "ethcore-db"
version = "1.2.0"
authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs"
[build-dependencies]
syntex = "*"
ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies]
ethcore-util = { path = "../util" }
clippy = { version = "0.0.67", optional = true}
ethcore-devtools = { path = "../devtools" }
ethcore-ipc = { path = "../ipc/rpc" }
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
semver = "0.2"
ethcore-ipc-nano = { path = "../ipc/nano" }
[features]
dev = ["clippy"]

43
db/build.rs Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate syntex;
extern crate ethcore_ipc_codegen as codegen;
use std::env;
use std::path::Path;
pub fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
// ipc pass
{
let src = Path::new("src/lib.rs.in");
let dst = Path::new(&out_dir).join("lib.intermediate.rs.in");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
// binary serialization pass
{
let src = Path::new(&out_dir).join("lib.intermediate.rs.in");
let dst = Path::new(&out_dir).join("lib.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}
}

370
db/src/database.rs Normal file
View File

@ -0,0 +1,370 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Ethcore rocksdb ipc service
use traits::*;
use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBIterator,
IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction};
use std::collections::BTreeMap;
use std::sync::{RwLock};
use std::convert::From;
use ipc::IpcConfig;
use std::ops::*;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
impl From<String> for Error {
fn from(s: String) -> Error {
Error::RocksDb(s)
}
}
pub struct Database {
db: RwLock<Option<DB>>,
transactions: RwLock<BTreeMap<TransactionHandle, WriteBatch>>,
iterators: RwLock<BTreeMap<IteratorHandle, DBIterator>>,
}
impl Database {
pub fn new() -> Database {
Database {
db: RwLock::new(None),
transactions: RwLock::new(BTreeMap::new()),
iterators: RwLock::new(BTreeMap::new()),
}
}
}
#[derive(Ipc)]
impl DatabaseService for Database {
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error> {
let mut db = self.db.write().unwrap();
if db.is_some() { return Err(Error::AlreadyOpen); }
let mut opts = Options::new();
opts.set_max_open_files(256);
opts.create_if_missing(true);
opts.set_use_fsync(false);
opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction);
if let Some(size) = config.prefix_size {
let mut block_opts = BlockBasedOptions::new();
block_opts.set_index_type(IndexType::HashSearch);
opts.set_block_based_table_factory(&block_opts);
opts.set_prefix_extractor_fixed_size(size);
}
*db = Some(try!(DB::open(&opts, &path)));
Ok(())
}
fn close(&self) -> Result<(), Error> {
let mut db = self.db.write().unwrap();
if db.is_none() { return Err(Error::IsClosed); }
// TODO: wait for transactions to expire/close here?
if self.transactions.read().unwrap().len() > 0 { return Err(Error::UncommitedTransactions); }
*db = None;
Ok(())
}
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
try!(db.put(key, value));
Ok(())
}
fn delete(&self, key: &[u8]) -> Result<(), Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
try!(db.delete(key));
Ok(())
}
fn write(&self, handle: TransactionHandle) -> Result<(), Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut transactions = self.transactions.write().unwrap();
let batch = try!(
transactions.remove(&handle).ok_or(Error::TransactionUnknown)
);
try!(db.write(batch));
Ok(())
}
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
match try!(db.get(key)) {
Some(db_vec) => Ok(Some(db_vec.to_vec())),
None => Ok(None),
}
}
fn get_by_prefix(&self, prefix: &[u8]) -> Result<Option<Vec<u8>>, Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut iter = db.iterator(IteratorMode::From(prefix, Direction::Forward));
match iter.next() {
// TODO: use prefix_same_as_start read option (not availabele in C API currently)
Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Ok(Some(v.to_vec())) } else { Ok(None) },
_ => Ok(None)
}
}
fn is_empty(&self) -> Result<bool, Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
Ok(db.iterator(IteratorMode::Start).next().is_none())
}
fn iter(&self) -> Result<IteratorHandle, Error> {
let db_lock = self.db.read().unwrap();
let db = try!(db_lock.as_ref().ok_or(Error::IsClosed));
let mut iterators = self.iterators.write().unwrap();
let next_iterator = iterators.keys().last().unwrap_or(&0) + 1;
iterators.insert(next_iterator, db.iterator(IteratorMode::Start));
Ok(next_iterator)
}
fn iter_next(&self, handle: IteratorHandle) -> Option<KeyValue>
{
let mut iterators = self.iterators.write().unwrap();
let mut iterator = match iterators.get_mut(&handle) {
Some(some_iterator) => some_iterator,
None => { return None; },
};
iterator.next().and_then(|(some_key, some_val)| {
Some(KeyValue {
key: some_key.to_vec(),
value: some_val.to_vec(),
})
})
}
fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error>
{
let mut transactions = self.transactions.write().unwrap();
let batch = try!(
transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown)
);
try!(batch.put(&key, &value));
Ok(())
}
fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error> {
let mut transactions = self.transactions.write().unwrap();
let batch = try!(
transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown)
);
try!(batch.delete(&key));
Ok(())
}
fn new_transaction(&self) -> TransactionHandle {
let mut transactions = self.transactions.write().unwrap();
let next_transaction = transactions.keys().last().unwrap_or(&0) + 1;
transactions.insert(next_transaction, WriteBatch::new());
next_transaction
}
}
// TODO : put proper at compile-time
impl IpcConfig for Database {}
#[cfg(test)]
mod test {
use super::Database;
use traits::*;
use devtools::*;
#[test]
fn can_be_created() {
let db = Database::new();
assert!(db.is_empty().is_err());
}
#[test]
fn can_be_open_empty() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
assert!(db.is_empty().is_ok());
}
#[test]
fn can_store_key() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
assert!(!db.is_empty().unwrap());
}
#[test]
fn can_retrieve() {
let db = Database::new();
let path = RandomTempPath::create_dir();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap();
db.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
db.close().unwrap();
db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap();
assert_eq!(db.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
}
}
#[cfg(test)]
mod client_tests {
use super::{DatabaseClient, Database};
use traits::*;
use devtools::*;
use nanoipc;
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
fn init_worker(addr: &str) -> nanoipc::Worker<Database> {
let mut worker = nanoipc::Worker::<Database>::new(&Arc::new(Database::new()));
worker.add_duplex(addr).unwrap();
worker
}
#[test]
fn can_call_handshake() {
let url = "ipc:///tmp/parity-db-ipc-test-10.ipc";
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
let hs = client.handshake();
worker_should_exit.store(true, Ordering::Relaxed);
assert!(hs.is_ok());
}
#[test]
fn can_open_db() {
let url = "ipc:///tmp/parity-db-ipc-test-20.ipc";
let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
assert!(client.is_empty().unwrap());
worker_should_exit.store(true, Ordering::Relaxed);
}
#[test]
fn can_put() {
let url = "ipc:///tmp/parity-db-ipc-test-30.ipc";
let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
worker_should_exit.store(true, Ordering::Relaxed);
}
#[test]
fn can_put_and_read() {
let url = "ipc:///tmp/parity-db-ipc-test-40.ipc";
let path = RandomTempPath::create_dir();
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let client = nanoipc::init_duplex_client::<DatabaseClient<_>>(url).unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
client.put("xxx".as_bytes(), "1".as_bytes()).unwrap();
client.close().unwrap();
client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap();
assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec());
worker_should_exit.store(true, Ordering::Relaxed);
}
}

20
db/src/lib.rs Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Database ipc service
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/lib.rs"));

25
db/src/lib.rs.in Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate ethcore_ipc as ipc;
extern crate rocksdb;
extern crate ethcore_devtools as devtools;
extern crate semver;
extern crate ethcore_ipc_nano as nanoipc;
extern crate ethcore_util as util;
pub mod database;
pub mod traits;

0
db/src/service.rs Normal file
View File

73
db/src/traits.rs Normal file
View File

@ -0,0 +1,73 @@
//! Ethcore database trait
use ipc::BinaryConvertable;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
pub type TransactionHandle = u32;
pub type IteratorHandle = u32;
#[derive(Binary)]
pub struct KeyValue {
pub key: Vec<u8>,
pub value: Vec<u8>,
}
#[derive(Debug, Binary)]
pub enum Error {
AlreadyOpen,
IsClosed,
RocksDb(String),
TransactionUnknown,
IteratorUnknown,
UncommitedTransactions,
}
/// Database configuration
#[derive(Binary)]
pub struct DatabaseConfig {
/// Optional prefix size in bytes. Allows lookup by partial key.
pub prefix_size: Option<usize>
}
pub trait DatabaseService {
/// Opens database in the specified path
fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error>;
/// Closes database
fn close(&self) -> Result<(), Error>;
/// Insert a key-value pair in the transaction. Any existing value value will be overwritten.
fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error>;
/// Delete value by key.
fn delete(&self, key: &[u8]) -> Result<(), Error>;
/// Insert a key-value pair in the transaction. Any existing value value will be overwritten.
fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error>;
/// Delete value by key using transaction
fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error>;
/// Commit transaction to database.
fn write(&self, tr: TransactionHandle) -> Result<(), Error>;
/// Initiate new transaction on database
fn new_transaction(&self) -> TransactionHandle;
/// Get value by key.
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error>;
/// Get value by partial key. Prefix size should match configured prefix size.
fn get_by_prefix(&self, prefix: &[u8]) -> Result<Option<Vec<u8>>, Error>;
/// Check if there is anything in the database.
fn is_empty(&self) -> Result<bool, Error>;
/// Get handle to iterate through keys
fn iter(&self) -> Result<IteratorHandle, Error>;
/// Next key-value for the the given iterator
fn iter_next(&self, iterator: IteratorHandle) -> Option<KeyValue>;
}

View File

@ -21,7 +21,7 @@ use std::path::PathBuf;
use util::*; use util::*;
use util::panics::*; use util::panics::*;
use views::BlockView; use views::BlockView;
use error::*; use error::{Error, ImportError, ExecutionError, BlockError, ImportResult};
use header::{BlockNumber, Header}; use header::{BlockNumber, Header};
use state::State; use state::State;
use spec::Spec; use spec::Spec;
@ -37,7 +37,8 @@ use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo}; use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter}; use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, TraceFilter};
use client::Error as ClientError;
use env_info::EnvInfo; use env_info::EnvInfo;
use executive::{Executive, Executed, TransactOptions, contract_address}; use executive::{Executive, Executed, TransactOptions, contract_address};
use receipt::LocalizedReceipt; use receipt::LocalizedReceipt;
@ -101,7 +102,7 @@ const CLIENT_DB_VER_STR: &'static str = "5.3";
impl Client<CanonVerifier> { impl Client<CanonVerifier> {
/// Create a new client with given spec and DB path. /// Create a new client with given spec and DB path.
pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Arc<Client> { pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client>, ClientError> {
Client::<CanonVerifier>::new_with_verifier(config, spec, path, message_channel) Client::<CanonVerifier>::new_with_verifier(config, spec, path, message_channel)
} }
} }
@ -125,11 +126,11 @@ pub fn append_path(path: &Path, item: &str) -> String {
impl<V> Client<V> where V: Verifier { impl<V> Client<V> where V: Verifier {
/// Create a new client with given spec and DB path and custom verifier. /// Create a new client with given spec and DB path and custom verifier.
pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Arc<Client<V>> { pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel<NetSyncMessage> ) -> Result<Arc<Client<V>>, ClientError> {
let path = get_db_path(path, config.pruning, spec.genesis_header().hash()); let path = get_db_path(path, config.pruning, spec.genesis_header().hash());
let gb = spec.genesis_block(); let gb = spec.genesis_block();
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path)); let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path));
let tracedb = Arc::new(TraceDB::new(config.tracing, &path, chain.clone())); let tracedb = Arc::new(try!(TraceDB::new(config.tracing, &path, chain.clone())));
let mut state_db = journaldb::new(&append_path(&path, "state"), config.pruning); let mut state_db = journaldb::new(&append_path(&path, "state"), config.pruning);
@ -143,7 +144,7 @@ impl<V> Client<V> where V: Verifier {
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
panic_handler.forward_from(&block_queue); panic_handler.forward_from(&block_queue);
Arc::new(Client { let client = Client {
chain: chain, chain: chain,
tracedb: tracedb, tracedb: tracedb,
engine: engine, engine: engine,
@ -154,7 +155,9 @@ impl<V> Client<V> where V: Verifier {
panic_handler: panic_handler, panic_handler: panic_handler,
verifier: PhantomData, verifier: PhantomData,
vm_factory: Arc::new(EvmFactory::new(config.vm_type)), vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
}) };
Ok(Arc::new(client))
} }
/// Flush the block import queue. /// Flush the block import queue.
@ -371,28 +374,28 @@ impl<V> Client<V> where V: Verifier {
self.chain.configure_cache(pref_cache_size, max_cache_size); self.chain.configure_cache(pref_cache_size, max_cache_size);
} }
fn block_hash(chain: &BlockChain, id: BlockId) -> Option<H256> { fn block_hash(chain: &BlockChain, id: BlockID) -> Option<H256> {
match id { match id {
BlockId::Hash(hash) => Some(hash), BlockID::Hash(hash) => Some(hash),
BlockId::Number(number) => chain.block_hash(number), BlockID::Number(number) => chain.block_hash(number),
BlockId::Earliest => chain.block_hash(0), BlockID::Earliest => chain.block_hash(0),
BlockId::Latest => Some(chain.best_block_hash()) BlockID::Latest => Some(chain.best_block_hash())
} }
} }
fn block_number(&self, id: BlockId) -> Option<BlockNumber> { fn block_number(&self, id: BlockID) -> Option<BlockNumber> {
match id { match id {
BlockId::Number(number) => Some(number), BlockID::Number(number) => Some(number),
BlockId::Hash(ref hash) => self.chain.block_number(hash), BlockID::Hash(ref hash) => self.chain.block_number(hash),
BlockId::Earliest => Some(0), BlockID::Earliest => Some(0),
BlockId::Latest => Some(self.chain.best_block_number()) BlockID::Latest => Some(self.chain.best_block_number())
} }
} }
fn transaction_address(&self, id: TransactionId) -> Option<TransactionAddress> { fn transaction_address(&self, id: TransactionID) -> Option<TransactionAddress> {
match id { match id {
TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), TransactionID::Hash(ref hash) => self.chain.transaction_address(hash),
TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { TransactionID::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress {
block_hash: hash, block_hash: hash,
index: index index: index
}) })
@ -402,7 +405,7 @@ impl<V> Client<V> where V: Verifier {
impl<V> BlockChainClient for Client<V> where V: Verifier { impl<V> BlockChainClient for Client<V> where V: Verifier {
fn call(&self, t: &SignedTransaction) -> Result<Executed, ExecutionError> { fn call(&self, t: &SignedTransaction) -> Result<Executed, ExecutionError> {
let header = self.block_header(BlockId::Latest).unwrap(); let header = self.block_header(BlockID::Latest).unwrap();
let view = HeaderView::new(&header); let view = HeaderView::new(&header);
let last_hashes = self.build_last_hashes(view.hash()); let last_hashes = self.build_last_hashes(view.hash());
let env_info = EnvInfo { let env_info = EnvInfo {
@ -503,11 +506,11 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
(Some(b), invalid_transactions) (Some(b), invalid_transactions)
} }
fn block_header(&self, id: BlockId) -> Option<Bytes> { fn block_header(&self, id: BlockID) -> Option<Bytes> {
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()))
} }
fn block_body(&self, id: BlockId) -> Option<Bytes> { fn block_body(&self, id: BlockID) -> Option<Bytes> {
Self::block_hash(&self.chain, id).and_then(|hash| { Self::block_hash(&self.chain, id).and_then(|hash| {
self.chain.block(&hash).map(|bytes| { self.chain.block(&hash).map(|bytes| {
let rlp = Rlp::new(&bytes); let rlp = Rlp::new(&bytes);
@ -519,13 +522,13 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
}) })
} }
fn block(&self, id: BlockId) -> Option<Bytes> { fn block(&self, id: BlockID) -> Option<Bytes> {
Self::block_hash(&self.chain, id).and_then(|hash| { Self::block_hash(&self.chain, id).and_then(|hash| {
self.chain.block(&hash) self.chain.block(&hash)
}) })
} }
fn block_status(&self, id: BlockId) -> BlockStatus { fn block_status(&self, id: BlockID) -> BlockStatus {
match Self::block_hash(&self.chain, id) { match Self::block_hash(&self.chain, id) {
Some(ref hash) if self.chain.is_known(hash) => BlockStatus::InChain, Some(ref hash) if self.chain.is_known(hash) => BlockStatus::InChain,
Some(hash) => self.block_queue.block_status(&hash), Some(hash) => self.block_queue.block_status(&hash),
@ -533,7 +536,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
} }
} }
fn block_total_difficulty(&self, id: BlockId) -> Option<U256> { fn block_total_difficulty(&self, id: BlockID) -> Option<U256> {
Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty) Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty)
} }
@ -541,7 +544,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
self.state().nonce(address) self.state().nonce(address)
} }
fn block_hash(&self, id: BlockId) -> Option<H256> { fn block_hash(&self, id: BlockID) -> Option<H256> {
Self::block_hash(&self.chain, id) Self::block_hash(&self.chain, id)
} }
@ -557,16 +560,16 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
self.state().storage_at(address, position) self.state().storage_at(address, position)
} }
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> { fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction> {
self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) self.transaction_address(id).and_then(|address| self.chain.transaction(&address))
} }
fn uncle(&self, id: UncleId) -> Option<Header> { fn uncle(&self, id: UncleID) -> Option<Header> {
let index = id.1; let index = id.1;
self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index)) self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index))
} }
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> { fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
self.transaction_address(id).and_then(|address| { self.transaction_address(id).and_then(|address| {
let t = self.chain.block(&address.block_hash) let t = self.chain.block(&address.block_hash)
.and_then(|block| BlockView::new(&block).localized_transaction_at(address.index)); .and_then(|block| BlockView::new(&block).localized_transaction_at(address.index));
@ -625,7 +628,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
if self.chain.is_known(&header.sha3()) { if self.chain.is_known(&header.sha3()) {
return Err(x!(ImportError::AlreadyInChain)); return Err(x!(ImportError::AlreadyInChain));
} }
if self.block_status(BlockId::Hash(header.parent_hash())) == BlockStatus::Unknown { if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown {
return Err(x!(BlockError::UnknownParent(header.parent_hash()))); return Err(x!(BlockError::UnknownParent(header.parent_hash())));
} }
} }
@ -650,7 +653,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
} }
} }
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>> { fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockID, to_block: BlockID) -> Option<Vec<BlockNumber>> {
match (self.block_number(from_block), self.block_number(to_block)) { match (self.block_number(from_block), self.block_number(to_block)) {
(Some(from), Some(to)) => Some(self.chain.blocks_with_bloom(bloom, from, to)), (Some(from), Some(to)) => Some(self.chain.blocks_with_bloom(bloom, from, to)),
_ => None _ => None
@ -721,20 +724,20 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
let trace_address = trace.address; let trace_address = trace.address;
self.transaction_address(trace.transaction) self.transaction_address(trace.transaction)
.and_then(|tx_address| { .and_then(|tx_address| {
self.block_number(BlockId::Hash(tx_address.block_hash)) self.block_number(BlockID::Hash(tx_address.block_hash))
.and_then(|number| self.tracedb.trace(number, tx_address.index, trace_address)) .and_then(|number| self.tracedb.trace(number, tx_address.index, trace_address))
}) })
} }
fn transaction_traces(&self, transaction: TransactionId) -> Option<Vec<LocalizedTrace>> { fn transaction_traces(&self, transaction: TransactionID) -> Option<Vec<LocalizedTrace>> {
self.transaction_address(transaction) self.transaction_address(transaction)
.and_then(|tx_address| { .and_then(|tx_address| {
self.block_number(BlockId::Hash(tx_address.block_hash)) self.block_number(BlockID::Hash(tx_address.block_hash))
.and_then(|number| self.tracedb.transaction_traces(number, tx_address.index)) .and_then(|number| self.tracedb.transaction_traces(number, tx_address.index))
}) })
} }
fn block_traces(&self, block: BlockId) -> Option<Vec<LocalizedTrace>> { fn block_traces(&self, block: BlockID) -> Option<Vec<LocalizedTrace>> {
self.block_number(block) self.block_number(block)
.and_then(|number| self.tracedb.block_traces(number)) .and_then(|number| self.tracedb.block_traces(number))
} }

View File

@ -0,0 +1,23 @@
use trace::Error as TraceError;
use std::fmt::{Display, Formatter, Error as FmtError};
/// Client configuration errors.
#[derive(Debug)]
pub enum Error {
/// TraceDB configuration error.
Trace(TraceError),
}
impl From<TraceError> for Error {
fn from(err: TraceError) -> Self {
Error::Trace(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Error::Trace(ref err) => write!(f, "{}", err)
}
}
}

View File

@ -18,11 +18,13 @@
mod client; mod client;
mod config; mod config;
mod error;
mod test_client; mod test_client;
mod trace; mod trace;
pub use self::client::*; pub use self::client::*;
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch, VMType}; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch, VMType};
pub use self::error::Error;
pub use types::ids::*; pub use types::ids::*;
pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::trace::Filter as TraceFilter; pub use self::trace::Filter as TraceFilter;
@ -48,26 +50,26 @@ use evm::Factory as EvmFactory;
/// Blockchain database client. Owns and manages a blockchain and a block queue. /// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send { pub trait BlockChainClient : Sync + Send {
/// Get raw block header data by block id. /// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<Bytes>; fn block_header(&self, id: BlockID) -> Option<Bytes>;
/// Get raw block body data by block id. /// Get raw block body data by block id.
/// Block body is an RLP list of two items: uncles and transactions. /// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, id: BlockId) -> Option<Bytes>; fn block_body(&self, id: BlockID) -> Option<Bytes>;
/// Get raw block data by block header hash. /// Get raw block data by block header hash.
fn block(&self, id: BlockId) -> Option<Bytes>; fn block(&self, id: BlockID) -> Option<Bytes>;
/// Get block status by block header hash. /// Get block status by block header hash.
fn block_status(&self, id: BlockId) -> BlockStatus; fn block_status(&self, id: BlockID) -> BlockStatus;
/// Get block total difficulty. /// Get block total difficulty.
fn block_total_difficulty(&self, id: BlockId) -> Option<U256>; fn block_total_difficulty(&self, id: BlockID) -> Option<U256>;
/// Get address nonce. /// Get address nonce.
fn nonce(&self, address: &Address) -> U256; fn nonce(&self, address: &Address) -> U256;
/// Get block hash. /// Get block hash.
fn block_hash(&self, id: BlockId) -> Option<H256>; fn block_hash(&self, id: BlockID) -> Option<H256>;
/// Get address code. /// Get address code.
fn code(&self, address: &Address) -> Option<Bytes>; fn code(&self, address: &Address) -> Option<Bytes>;
@ -79,13 +81,13 @@ pub trait BlockChainClient : Sync + Send {
fn storage_at(&self, address: &Address, position: &H256) -> H256; fn storage_at(&self, address: &Address, position: &H256) -> H256;
/// Get transaction with given hash. /// Get transaction with given hash.
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>; fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction>;
/// Get uncle with given id. /// Get uncle with given id.
fn uncle(&self, id: UncleId) -> Option<Header>; fn uncle(&self, id: UncleID) -> Option<Header>;
/// Get transaction receipt with given hash. /// Get transaction receipt with given hash.
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>; fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt>;
/// Get a tree route between `from` and `to`. /// Get a tree route between `from` and `to`.
/// See `BlockChain::tree_route`. /// See `BlockChain::tree_route`.
@ -112,11 +114,11 @@ pub trait BlockChainClient : Sync + Send {
/// Get the best block header. /// Get the best block header.
fn best_block_header(&self) -> Bytes { fn best_block_header(&self) -> Bytes {
// TODO: lock blockchain only once // TODO: lock blockchain only once
self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() self.block_header(BlockID::Hash(self.chain_info().best_block_hash)).unwrap()
} }
/// Returns numbers of blocks containing given bloom. /// Returns numbers of blocks containing given bloom.
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>; fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockID, to_block: BlockID) -> Option<Vec<BlockNumber>>;
/// Returns logs matching given filter. /// Returns logs matching given filter.
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>; fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
@ -143,10 +145,10 @@ pub trait BlockChainClient : Sync + Send {
fn trace(&self, trace: TraceId) -> Option<LocalizedTrace>; fn trace(&self, trace: TraceId) -> Option<LocalizedTrace>;
/// Returns traces created by transaction. /// Returns traces created by transaction.
fn transaction_traces(&self, trace: TransactionId) -> Option<Vec<LocalizedTrace>>; fn transaction_traces(&self, trace: TransactionID) -> Option<Vec<LocalizedTrace>>;
/// Returns traces created by transaction from block. /// Returns traces created by transaction from block.
fn block_traces(&self, trace: BlockId) -> Option<Vec<LocalizedTrace>>; fn block_traces(&self, trace: BlockID) -> Option<Vec<LocalizedTrace>>;
/// Get last hashes starting from best block. /// Get last hashes starting from best block.
fn last_hashes(&self) -> LastHashes; fn last_hashes(&self) -> LastHashes;

View File

@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
use util::*; use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute; use blockchain::TreeRoute;
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes}; use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes};
use header::{Header as BlockHeader, BlockNumber}; use header::{Header as BlockHeader, BlockNumber};
use filter::Filter; use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
@ -58,7 +58,7 @@ pub struct TestBlockChainClient {
/// Execution result. /// Execution result.
pub execution_result: RwLock<Option<Executed>>, pub execution_result: RwLock<Option<Executed>>,
/// Transaction receipts. /// Transaction receipts.
pub receipts: RwLock<HashMap<TransactionId, LocalizedReceipt>>, pub receipts: RwLock<HashMap<TransactionID, LocalizedReceipt>>,
/// Block queue size. /// Block queue size.
pub queue_size: AtomicUsize, pub queue_size: AtomicUsize,
} }
@ -106,7 +106,7 @@ impl TestBlockChainClient {
} }
/// Set the transaction receipt result /// Set the transaction receipt result
pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) { pub fn set_transaction_receipt(&self, id: TransactionID, receipt: LocalizedReceipt) {
self.receipts.write().unwrap().insert(id, receipt); self.receipts.write().unwrap().insert(id, receipt);
} }
@ -191,11 +191,23 @@ impl TestBlockChainClient {
} }
} }
/// TODO: /// Make a bad block by setting invalid extra data.
pub fn corrupt_block(&mut self, n: BlockNumber) { pub fn corrupt_block(&mut self, n: BlockNumber) {
let hash = self.block_hash(BlockId::Number(n)).unwrap(); let hash = self.block_hash(BlockID::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); let mut header: BlockHeader = decode(&self.block_header(BlockID::Number(n)).unwrap());
header.parent_hash = H256::new(); header.extra_data = b"This extra data is way too long to be considered valid".to_vec();
let mut rlp = RlpStream::new_list(3);
rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1);
rlp.append_raw(&rlp::NULL_RLP, 1);
self.blocks.write().unwrap().insert(hash, rlp.out());
}
/// Make a bad block by setting invalid parent hash.
pub fn corrupt_block_parent(&mut self, n: BlockNumber) {
let hash = self.block_hash(BlockID::Number(n)).unwrap();
let mut header: BlockHeader = decode(&self.block_header(BlockID::Number(n)).unwrap());
header.parent_hash = H256::from(42);
let mut rlp = RlpStream::new_list(3); let mut rlp = RlpStream::new_list(3);
rlp.append(&header); rlp.append(&header);
rlp.append_raw(&rlp::NULL_RLP, 1); rlp.append_raw(&rlp::NULL_RLP, 1);
@ -210,12 +222,12 @@ impl TestBlockChainClient {
blocks_read[&index].clone() blocks_read[&index].clone()
} }
fn block_hash(&self, id: BlockId) -> Option<H256> { fn block_hash(&self, id: BlockID) -> Option<H256> {
match id { match id {
BlockId::Hash(hash) => Some(hash), BlockID::Hash(hash) => Some(hash),
BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), BlockID::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(),
BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), BlockID::Earliest => self.numbers.read().unwrap().get(&0).cloned(),
BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() BlockID::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned()
} }
} }
} }
@ -225,12 +237,12 @@ impl BlockChainClient for TestBlockChainClient {
Ok(self.execution_result.read().unwrap().clone().unwrap()) Ok(self.execution_result.read().unwrap().clone().unwrap())
} }
fn block_total_difficulty(&self, _id: BlockId) -> Option<U256> { fn block_total_difficulty(&self, _id: BlockID) -> Option<U256> {
Some(U256::zero()) Some(U256::zero())
} }
fn block_hash(&self, _id: BlockId) -> Option<H256> { fn block_hash(&self, id: BlockID) -> Option<H256> {
unimplemented!(); Self::block_hash(self, id)
} }
fn nonce(&self, address: &Address) -> U256 { fn nonce(&self, address: &Address) -> U256 {
@ -249,19 +261,19 @@ impl BlockChainClient for TestBlockChainClient {
self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new) self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)
} }
fn transaction(&self, _id: TransactionId) -> Option<LocalizedTransaction> { fn transaction(&self, _id: TransactionID) -> Option<LocalizedTransaction> {
unimplemented!(); unimplemented!();
} }
fn uncle(&self, _id: UncleId) -> Option<BlockHeader> { fn uncle(&self, _id: UncleID) -> Option<BlockHeader> {
unimplemented!(); unimplemented!();
} }
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> { fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
self.receipts.read().unwrap().get(&id).cloned() self.receipts.read().unwrap().get(&id).cloned()
} }
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option<Vec<BlockNumber>> { fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockID, _to_block: BlockID) -> Option<Vec<BlockNumber>> {
unimplemented!(); unimplemented!();
} }
@ -281,11 +293,11 @@ impl BlockChainClient for TestBlockChainClient {
Err(block) Err(block)
} }
fn block_header(&self, id: BlockId) -> Option<Bytes> { fn block_header(&self, id: BlockID) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
} }
fn block_body(&self, id: BlockId) -> Option<Bytes> { fn block_body(&self, id: BlockID) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| {
let mut stream = RlpStream::new_list(2); let mut stream = RlpStream::new_list(2);
stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1);
@ -294,14 +306,14 @@ impl BlockChainClient for TestBlockChainClient {
})) }))
} }
fn block(&self, id: BlockId) -> Option<Bytes> { fn block(&self, id: BlockID) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned())
} }
fn block_status(&self, id: BlockId) -> BlockStatus { fn block_status(&self, id: BlockID) -> BlockStatus {
match id { match id {
BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, BlockID::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain,
BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, BlockID::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain,
_ => BlockStatus::Unknown _ => BlockStatus::Unknown
} }
} }
@ -442,11 +454,11 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!(); unimplemented!();
} }
fn transaction_traces(&self, _trace: TransactionId) -> Option<Vec<LocalizedTrace>> { fn transaction_traces(&self, _trace: TransactionID) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); unimplemented!();
} }
fn block_traces(&self, _trace: BlockId) -> Option<Vec<LocalizedTrace>> { fn block_traces(&self, _trace: BlockID) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); unimplemented!();
} }
} }

View File

@ -7,7 +7,7 @@ use header::BlockNumber;
use trace::DatabaseExtras as TraceDatabaseExtras; use trace::DatabaseExtras as TraceDatabaseExtras;
use blockchain::{BlockChain, BlockProvider}; use blockchain::{BlockChain, BlockProvider};
use extras::TransactionAddress; use extras::TransactionAddress;
use super::BlockId; use super::BlockID;
impl TraceDatabaseExtras for BlockChain { impl TraceDatabaseExtras for BlockChain {
fn block_hash(&self, block_number: BlockNumber) -> Option<H256> { fn block_hash(&self, block_number: BlockNumber) -> Option<H256> {
@ -30,7 +30,7 @@ impl TraceDatabaseExtras for BlockChain {
/// Easy to use trace filter. /// Easy to use trace filter.
pub struct Filter { pub struct Filter {
/// Range of filtering. /// Range of filtering.
pub range: Range<BlockId>, pub range: Range<BlockID>,
/// From address. /// From address.
pub from_address: Vec<Address>, pub from_address: Vec<Address>,
/// To address. /// To address.

View File

@ -19,6 +19,7 @@
use util::*; use util::*;
use header::BlockNumber; use header::BlockNumber;
use basic_types::LogBloom; use basic_types::LogBloom;
use client::Error as ClientError;
pub use types::executed::ExecutionError; pub use types::executed::ExecutionError;
@ -134,6 +135,8 @@ pub enum ImportError {
#[derive(Debug)] #[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore. /// General error type which should be capable of representing all errors in ethcore.
pub enum Error { pub enum Error {
/// Client configuration error.
Client(ClientError),
/// Error concerning a utility. /// Error concerning a utility.
Util(UtilError), Util(UtilError),
/// Error concerning block processing. /// Error concerning block processing.
@ -155,6 +158,12 @@ pub enum Error {
/// Result of import block operation. /// Result of import block operation.
pub type ImportResult = Result<H256, Error>; pub type ImportResult = Result<H256, Error>;
impl From<ClientError> for Error {
fn from(err: ClientError) -> Error {
Error::Client(err)
}
}
impl From<TransactionError> for Error { impl From<TransactionError> for Error {
fn from(err: TransactionError) -> Error { fn from(err: TransactionError) -> Error {
Error::Transaction(err) Error::Transaction(err)

View File

@ -18,16 +18,16 @@
use util::hash::*; use util::hash::*;
use util::sha3::*; use util::sha3::*;
use client::BlockId; use client::BlockID;
use log_entry::LogEntry; use log_entry::LogEntry;
/// Blockchain Filter. /// Blockchain Filter.
pub struct Filter { pub struct Filter {
/// Blockchain will be searched from this block. /// Blockchain will be searched from this block.
pub from_block: BlockId, pub from_block: BlockID,
/// Till this block. /// Till this block.
pub to_block: BlockId, pub to_block: BlockID,
/// Search addresses. /// Search addresses.
/// ///
@ -102,14 +102,14 @@ mod tests {
use std::str::FromStr; use std::str::FromStr;
use util::hash::*; use util::hash::*;
use filter::Filter; use filter::Filter;
use client::BlockId; use client::BlockID;
use log_entry::LogEntry; use log_entry::LogEntry;
#[test] #[test]
fn test_bloom_possibilities_none() { fn test_bloom_possibilities_none() {
let none_filter = Filter { let none_filter = Filter {
from_block: BlockId::Earliest, from_block: BlockID::Earliest,
to_block: BlockId::Latest, to_block: BlockID::Latest,
address: None, address: None,
topics: [None, None, None, None] topics: [None, None, None, None]
}; };
@ -123,8 +123,8 @@ mod tests {
#[test] #[test]
fn test_bloom_possibilities_single_address_and_topic() { fn test_bloom_possibilities_single_address_and_topic() {
let filter = Filter { let filter = Filter {
from_block: BlockId::Earliest, from_block: BlockID::Earliest,
to_block: BlockId::Latest, to_block: BlockID::Latest,
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
topics: [ topics: [
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
@ -139,8 +139,8 @@ mod tests {
#[test] #[test]
fn test_bloom_possibilities_single_address_and_many_topics() { fn test_bloom_possibilities_single_address_and_many_topics() {
let filter = Filter { let filter = Filter {
from_block: BlockId::Earliest, from_block: BlockID::Earliest,
to_block: BlockId::Latest, to_block: BlockID::Latest,
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
topics: [ topics: [
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),
@ -156,8 +156,8 @@ mod tests {
#[test] #[test]
fn test_bloom_possibilites_multiple_addresses_and_topics() { fn test_bloom_possibilites_multiple_addresses_and_topics() {
let filter = Filter { let filter = Filter {
from_block: BlockId::Earliest, from_block: BlockID::Earliest,
to_block: BlockId::Latest, to_block: BlockID::Latest,
address: Some(vec![ address: Some(vec![
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(),
@ -185,8 +185,8 @@ mod tests {
#[test] #[test]
fn test_filter_matches() { fn test_filter_matches() {
let filter = Filter { let filter = Filter {
from_block: BlockId::Earliest, from_block: BlockID::Earliest,
to_block: BlockId::Latest, to_block: BlockID::Latest,
address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]),
topics: [ topics: [
Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]),

View File

@ -53,7 +53,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let temp = RandomTempPath::new(); let temp = RandomTempPath::new();
{ {
let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap();
for b in &blockchain.blocks_rlp() { for b in &blockchain.blocks_rlp() {
if Block::is_good(&b) { if Block::is_good(&b) {
let _ = client.import_block(b.clone()); let _ = client.import_block(b.clone());

View File

@ -61,7 +61,7 @@ impl ClientService {
info!("Starting {}", net_service.host_info()); info!("Starting {}", net_service.host_info());
info!("Configured for {} using {:?} engine", spec.name, spec.engine.name()); info!("Configured for {} using {:?} engine", spec.name, spec.engine.name());
let client = Client::new(config, spec, db_path, net_service.io().channel()); let client = try!(Client::new(config, spec, db_path, net_service.io().channel()));
panic_handler.forward_from(client.deref()); panic_handler.forward_from(client.deref());
let client_io = Arc::new(ClientIoHandler { let client_io = Arc::new(ClientIoHandler {
client: client.clone() client: client.clone()

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use client::{BlockChainClient, Client, ClientConfig, BlockId}; use client::{BlockChainClient, Client, ClientConfig, BlockID};
use block::IsBlock; use block::IsBlock;
use tests::helpers::*; use tests::helpers::*;
use common::*; use common::*;
@ -23,7 +23,7 @@ use devtools::*;
#[test] #[test]
fn imports_from_empty() { fn imports_from_empty() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
client.import_verified_blocks(&IoChannel::disconnected()); client.import_verified_blocks(&IoChannel::disconnected());
client.flush_queue(); client.flush_queue();
} }
@ -41,7 +41,7 @@ fn returns_state_root_basic() {
#[test] #[test]
fn imports_good_block() { fn imports_good_block() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let good_block = get_good_dummy_block(); let good_block = get_good_dummy_block();
if let Err(_) = client.import_block(good_block) { if let Err(_) = client.import_block(good_block) {
panic!("error importing block being good by definition"); panic!("error importing block being good by definition");
@ -49,16 +49,16 @@ fn imports_good_block() {
client.flush_queue(); client.flush_queue();
client.import_verified_blocks(&IoChannel::disconnected()); client.import_verified_blocks(&IoChannel::disconnected());
let block = client.block_header(BlockId::Number(1)).unwrap(); let block = client.block_header(BlockID::Number(1)).unwrap();
assert!(!block.is_empty()); assert!(!block.is_empty());
} }
#[test] #[test]
fn query_none_block() { fn query_none_block() {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let non_existant = client.block_header(BlockId::Number(188)); let non_existant = client.block_header(BlockID::Number(188));
assert!(non_existant.is_none()); assert!(non_existant.is_none());
} }
@ -66,7 +66,7 @@ fn query_none_block() {
fn query_bad_block() { fn query_bad_block() {
let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]); let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]);
let client = client_result.reference(); let client = client_result.reference();
let bad_block:Option<Bytes> = client.block_header(BlockId::Number(1)); let bad_block:Option<Bytes> = client.block_header(BlockID::Number(1));
assert!(bad_block.is_none()); assert!(bad_block.is_none());
} }
@ -87,7 +87,7 @@ fn returns_block_body() {
let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]);
let client = client_result.reference(); let client = client_result.reference();
let block = BlockView::new(&dummy_block); let block = BlockView::new(&dummy_block);
let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap(); let body = client.block_body(BlockID::Hash(block.header().hash())).unwrap();
let body = Rlp::new(&body); let body = Rlp::new(&body);
assert_eq!(body.item_count(), 2); assert_eq!(body.item_count(), 2);
assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]); assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]);
@ -98,7 +98,7 @@ fn returns_block_body() {
fn imports_block_sequence() { fn imports_block_sequence() {
let client_result = generate_dummy_client(6); let client_result = generate_dummy_client(6);
let client = client_result.reference(); let client = client_result.reference();
let block = client.block_header(BlockId::Number(5)).unwrap(); let block = client.block_header(BlockID::Number(5)).unwrap();
assert!(!block.is_empty()); assert!(!block.is_empty());
} }

View File

@ -139,7 +139,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans
pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> { pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>> {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
let test_spec = get_test_spec(); let test_spec = get_test_spec();
let test_engine = &test_spec.engine; let test_engine = &test_spec.engine;
let state_root = test_spec.genesis_header().state_root; let state_root = test_spec.genesis_header().state_root;
@ -205,7 +205,7 @@ pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting
pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> { pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<Client>> {
let dir = RandomTempPath::new(); let dir = RandomTempPath::new();
let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap();
for block in &blocks { for block in &blocks {
if let Err(_) = client.import_block(block.clone()) { if let Err(_) = client.import_block(block.clone()) {
panic!("panic importing block which is well-formed"); panic!("panic importing block which is well-formed");

View File

@ -16,6 +16,7 @@
//! Traces config. //! Traces config.
use bloomchain::Config as BloomConfig; use bloomchain::Config as BloomConfig;
use trace::Error;
/// 3-value enum. /// 3-value enum.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@ -30,10 +31,10 @@ pub enum Switch {
impl Switch { impl Switch {
/// Tries to turn old switch to new value. /// Tries to turn old switch to new value.
pub fn turn_to(&self, to: Switch) -> Result<bool, &'static str> { pub fn turn_to(&self, to: Switch) -> Result<bool, Error> {
match (*self, to) { match (*self, to) {
(Switch::On, Switch::On) | (Switch::On, Switch::Auto) | (Switch::Auto, Switch::On) => Ok(true), (Switch::On, Switch::On) | (Switch::On, Switch::Auto) | (Switch::Auto, Switch::On) => Ok(true),
(Switch::Off, Switch::On) => Err("Tracing can't be enabled"), (Switch::Off, Switch::On) => Err(Error::ResyncRequired),
_ => Ok(false), _ => Ok(false),
} }
} }

View File

@ -25,7 +25,7 @@ use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, Bloo
use util::{H256, H264, Database, DBTransaction}; use util::{H256, H264, Database, DBTransaction};
use header::BlockNumber; use header::BlockNumber;
use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest, use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest,
DatabaseExtras}; DatabaseExtras, Error};
use db::{Key, Writable, Readable, CacheUpdatePolicy}; use db::{Key, Writable, Readable, CacheUpdatePolicy};
use super::bloom::{TraceGroupPosition, BlockTracesBloom, BlockTracesBloomGroup}; use super::bloom::{TraceGroupPosition, BlockTracesBloom, BlockTracesBloomGroup};
use super::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces}; use super::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
@ -103,7 +103,7 @@ impl<T> BloomGroupDatabase for TraceDB<T> where T: DatabaseExtras {
impl<T> TraceDB<T> where T: DatabaseExtras { impl<T> TraceDB<T> where T: DatabaseExtras {
/// Creates new instance of `TraceDB`. /// Creates new instance of `TraceDB`.
pub fn new(config: Config, path: &Path, extras: Arc<T>) -> Self { pub fn new(config: Config, path: &Path, extras: Arc<T>) -> Result<Self, Error> {
let mut tracedb_path = path.to_path_buf(); let mut tracedb_path = path.to_path_buf();
tracedb_path.push("tracedb"); tracedb_path.push("tracedb");
let tracesdb = Database::open_default(tracedb_path.to_str().unwrap()).unwrap(); let tracesdb = Database::open_default(tracedb_path.to_str().unwrap()).unwrap();
@ -116,7 +116,7 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
None => Switch::Auto, None => Switch::Auto,
}; };
let enabled = old_tracing.turn_to(config.enabled).expect("Tracing can't be enabled. Resync required."); let enabled = try!(old_tracing.turn_to(config.enabled));
let encoded_tracing = match enabled { let encoded_tracing = match enabled {
true => [0x1], true => [0x1],
@ -126,14 +126,16 @@ impl<T> TraceDB<T> where T: DatabaseExtras {
tracesdb.put(b"enabled", &encoded_tracing).unwrap(); tracesdb.put(b"enabled", &encoded_tracing).unwrap();
tracesdb.put(b"version", TRACE_DB_VER).unwrap(); tracesdb.put(b"version", TRACE_DB_VER).unwrap();
TraceDB { let db = TraceDB {
traces: RwLock::new(HashMap::new()), traces: RwLock::new(HashMap::new()),
blooms: RwLock::new(HashMap::new()), blooms: RwLock::new(HashMap::new()),
tracesdb: tracesdb, tracesdb: tracesdb,
bloom_config: config.blooms, bloom_config: config.blooms,
enabled: enabled, enabled: enabled,
extras: extras, extras: extras,
} };
Ok(db)
} }
/// Returns traces for block with hash. /// Returns traces for block with hash.
@ -401,19 +403,19 @@ mod tests {
config.enabled = Switch::Auto; config.enabled = Switch::Auto;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), false); assert_eq!(tracedb.tracing_enabled(), false);
} }
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), false); assert_eq!(tracedb.tracing_enabled(), false);
} }
config.enabled = Switch::Off; config.enabled = Switch::Off;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), false); assert_eq!(tracedb.tracing_enabled(), false);
} }
} }
@ -427,26 +429,26 @@ mod tests {
config.enabled = Switch::On; config.enabled = Switch::On;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), true); assert_eq!(tracedb.tracing_enabled(), true);
} }
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), true); assert_eq!(tracedb.tracing_enabled(), true);
} }
config.enabled = Switch::Auto; config.enabled = Switch::Auto;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), true); assert_eq!(tracedb.tracing_enabled(), true);
} }
config.enabled = Switch::Off; config.enabled = Switch::Off;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), false); assert_eq!(tracedb.tracing_enabled(), false);
} }
} }
@ -461,12 +463,12 @@ mod tests {
config.enabled = Switch::Off; config.enabled = Switch::Off;
{ {
let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); let tracedb = TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap();
assert_eq!(tracedb.tracing_enabled(), true); assert_eq!(tracedb.tracing_enabled(), true);
} }
config.enabled = Switch::On; config.enabled = Switch::On;
TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)); // should panic! TraceDB::new(config.clone(), temp.as_path(), Arc::new(NoopExtras)).unwrap(); // should panic!
} }
fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest { fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest {
@ -526,7 +528,7 @@ mod tests {
extras.transaction_hashes.insert(0, vec![tx_0.clone()]); extras.transaction_hashes.insert(0, vec![tx_0.clone()]);
extras.transaction_hashes.insert(1, vec![tx_1.clone()]); extras.transaction_hashes.insert(1, vec![tx_1.clone()]);
let tracedb = TraceDB::new(config, temp.as_path(), Arc::new(extras)); let tracedb = TraceDB::new(config, temp.as_path(), Arc::new(extras)).unwrap();
// import block 0 // import block 0
let request = create_simple_import_request(0, block_0.clone()); let request = create_simple_import_request(0, block_0.clone());

View File

@ -0,0 +1,41 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! TraceDB errors.
use std::fmt::{Display, Formatter, Error as FmtError};
const RESYNC_ERR: &'static str =
"Your current parity installation has synced without transaction tracing.
To use Parity with transaction tracing, you'll need to resync with tracing.
To do this, remove or move away your current database and restart parity. e.g.:
> mv ~/.parity/906a34e69aec8c0d /tmp
> parity";
/// TraceDB errors.
#[derive(Debug)]
pub enum Error {
/// Returned when tracing is enabled,
/// but database does not contain traces of old transactions.
ResyncRequired,
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", RESYNC_ERR)
}
}

View File

@ -20,6 +20,7 @@ mod block;
mod bloom; mod bloom;
mod config; mod config;
mod db; mod db;
mod error;
mod executive_tracer; mod executive_tracer;
pub mod flat; pub mod flat;
mod import; mod import;
@ -29,6 +30,7 @@ pub use types::trace_types::*;
pub use self::block::BlockTraces; pub use self::block::BlockTraces;
pub use self::config::{Config, Switch}; pub use self::config::{Config, Switch};
pub use self::db::TraceDB; pub use self::db::TraceDB;
pub use self::error::Error;
pub use types::trace_types::trace::Trace; pub use types::trace_types::trace::Trace;
pub use self::noop_tracer::NoopTracer; pub use self::noop_tracer::NoopTracer;
pub use self::executive_tracer::ExecutiveTracer; pub use self::executive_tracer::ExecutiveTracer;

View File

@ -24,7 +24,7 @@ use std::collections::VecDeque;
/// Uniquely identifies block. /// Uniquely identifies block.
#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] #[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)]
pub enum BlockId { pub enum BlockID {
/// Block's sha3. /// Block's sha3.
/// Querying by hash is always faster. /// Querying by hash is always faster.
Hash(H256), Hash(H256),
@ -38,27 +38,27 @@ pub enum BlockId {
/// Uniquely identifies transaction. /// Uniquely identifies transaction.
#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] #[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)]
pub enum TransactionId { pub enum TransactionID {
/// Transaction's sha3. /// Transaction's sha3.
Hash(H256), Hash(H256),
/// Block id and transaction index within this block. /// Block id and transaction index within this block.
/// Querying by block position is always faster. /// Querying by block position is always faster.
Location(BlockId, usize) Location(BlockID, usize)
} }
/// Uniquely identifies Trace. /// Uniquely identifies Trace.
pub struct TraceId { pub struct TraceId {
/// Transaction /// Transaction
pub transaction: TransactionId, pub transaction: TransactionID,
/// Trace address within transaction. /// Trace address within transaction.
pub address: Vec<usize>, pub address: Vec<usize>,
} }
/// Uniquely identifies Uncle. /// Uniquely identifies Uncle.
#[derive(Debug)] #[derive(Debug)]
pub struct UncleId ( pub struct UncleID (
/// Block id. /// Block id.
pub BlockId, pub BlockID,
/// Position in block. /// Position in block.
pub usize pub usize
); );

View File

@ -87,6 +87,13 @@ fn field_name(builder: &aster::AstBuilder, arg: &Arg) -> ast::Ident {
} }
} }
pub fn replace_slice_u8(builder: &aster::AstBuilder, ty: &P<ast::Ty>) -> P<ast::Ty> {
if ::syntax::print::pprust::ty_to_string(&strip_ptr(ty)) == "[u8]" {
return builder.ty().id("Vec<u8>")
}
ty.clone()
}
fn push_invoke_signature_aster( fn push_invoke_signature_aster(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
implement: &ImplItem, implement: &ImplItem,
@ -111,8 +118,8 @@ fn push_invoke_signature_aster(
.attr().word("derive(Binary)") .attr().word("derive(Binary)")
.attr().word("allow(non_camel_case_types)") .attr().word("allow(non_camel_case_types)")
.struct_(name_str.as_str()) .struct_(name_str.as_str())
.field(arg_name.as_str()).ty() .field(arg_name.as_str())
.build(strip_ptr(arg_ty)); .ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty.clone()); arg_tys.push(arg_ty.clone());
@ -120,7 +127,7 @@ fn push_invoke_signature_aster(
let arg_name = format!("{}", field_name(builder, &arg)); let arg_name = format!("{}", field_name(builder, &arg));
let arg_ty = &arg.ty; let arg_ty = &arg.ty;
tree = tree.field(arg_name.as_str()).ty().build(strip_ptr(arg_ty)); tree = tree.field(arg_name.as_str()).ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty.clone()); arg_tys.push(arg_ty.clone());
} }
@ -406,7 +413,7 @@ fn implement_client_method_body(
request_serialization_statements.push( request_serialization_statements.push(
quote_stmt!(cx, let mut socket = socket_ref.deref_mut())); quote_stmt!(cx, let mut socket = socket_ref.deref_mut()));
request_serialization_statements.push( request_serialization_statements.push(
quote_stmt!(cx, ::ipc::invoke($index_ident, Vec::new(), &mut socket))); quote_stmt!(cx, ::ipc::invoke($index_ident, &None, &mut socket)));
request_serialization_statements request_serialization_statements
}; };

View File

@ -175,19 +175,31 @@ fn binary_expr_struct(
) -> Result<BinaryExpressions, Error> { ) -> Result<BinaryExpressions, Error> {
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| { let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { let index_ident = builder.id(format!("__field{}", index));
return quote_expr!(cx, 1); match raw_ident.as_ref() {
"u8" => {
quote_expr!(cx, 1)
},
"[u8]" => {
value_ident.and_then(|x| {
let field_id = builder.id(field.ident.unwrap());
Some(quote_expr!(cx, $x. $field_id .len()))
})
.unwrap_or_else(|| {
quote_expr!(cx, $index_ident .len())
} }
)
}
_ => {
let field_type_ident = builder.id( let field_type_ident = builder.id(
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))); &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
let field_type_ident_qualified = builder.id( let field_type_ident_qualified = builder.id(
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)))); replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
let index_ident = builder.id(format!("__field{}", index)); value_ident.and_then(|x|
value_ident.and_then(|x| { {
let field_id = builder.id(field.ident.unwrap()); let field_id = builder.id(field.ident.unwrap());
Some(quote_expr!(cx, Some(quote_expr!(cx,
match $field_type_ident_qualified::len_params() { match $field_type_ident_qualified::len_params() {
@ -195,10 +207,14 @@ fn binary_expr_struct(
_ => $x. $field_id .size(), _ => $x. $field_id .size(),
})) }))
}) })
.unwrap_or_else(|| quote_expr!(cx, match $field_type_ident_qualified::len_params() { .unwrap_or_else(|| {
quote_expr!(cx, match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => $index_ident .size(), _ => $index_ident .size(),
})) })
})
}
}
}).collect(); }).collect();
let first_size_expr = size_exprs[0].clone(); let first_size_expr = size_exprs[0].clone();
@ -233,11 +249,19 @@ fn binary_expr_struct(
}, },
}; };
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
match raw_ident.as_ref() {
"u8" => {
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap()); write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap());
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap()); write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap());
},
"[u8]" => {
write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
write_stmts.push(quote_stmt!(cx, let next_line = offset + size;).unwrap());
write_stmts.push(quote_stmt!(cx, length_stack.push_back(size);).unwrap());
write_stmts.push(quote_stmt!(cx, buffer[offset..next_line].clone_from_slice($member_expr); ).unwrap());
} }
else { _ => {
write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() { write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => { let size = $member_expr .size(); length_stack.push_back(size); size }, _ => { let size = $member_expr .size(); length_stack.push_back(size); size },
@ -245,21 +269,28 @@ fn binary_expr_struct(
write_stmts.push(quote_stmt!(cx, write_stmts.push(quote_stmt!(cx,
if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap()); if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap());
} }
}
write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap()); write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap());
let field_index = builder.id(&format!("{}", index)); let field_index = builder.id(&format!("{}", index));
map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap()); map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap());
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { match raw_ident.as_ref() {
map_stmts.push(quote_stmt!(cx, total += 1;).unwrap()); "u8" => {
} map_stmts.push(quote_stmt!(cx, total = total + 1;).unwrap());
else { },
"[u8]" => {
map_stmts.push(quote_stmt!(cx, let size = length_stack.pop_front().unwrap();).unwrap());
map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap());
},
_ => {
map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() { map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => length_stack.pop_front().unwrap(), _ => length_stack.pop_front().unwrap(),
}).unwrap()); }).unwrap());
map_stmts.push(quote_stmt!(cx, total += size;).unwrap()); map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap());
}
} }
}; };
@ -419,6 +450,30 @@ fn fields_sequence(
continue; continue;
} }
// special case for [u8], it just takes a byte sequence
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::DotDot));
if idx+1 != fields.len() {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
}
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::Comma));
continue;
}
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token(_sp, token::OpenDelim(token::Paren)));
tt.push( tt.push(
@ -513,6 +568,30 @@ fn named_fields_sequence(
continue; continue;
} }
// special case for [u8], it just takes a byte sequence
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::DotDot));
if idx+1 != fields.len() {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
}
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::Comma));
continue;
}
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token(_sp, token::OpenDelim(token::Paren)));
tt.push(Token( tt.push(Token(

View File

@ -116,6 +116,8 @@ impl<S> Worker<S> where S: IpcInterface<S> {
/// Polls all sockets, reads and dispatches method invocations /// Polls all sockets, reads and dispatches method invocations
pub fn poll(&mut self) { pub fn poll(&mut self) {
use std::io::Write;
let mut request = PollRequest::new(&mut self.polls[..]); let mut request = PollRequest::new(&mut self.polls[..]);
let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT); let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT);
@ -135,7 +137,7 @@ impl<S> Worker<S> where S: IpcInterface<S> {
// dispatching for ipc interface // dispatching for ipc interface
let result = self.service.dispatch_buf(method_num, payload); let result = self.service.dispatch_buf(method_num, payload);
if let Err(e) = socket.nb_write(&result) { if let Err(e) = socket.write(&result) {
warn!(target: "ipc", "Failed to write response: {:?}", e); warn!(target: "ipc", "Failed to write response: {:?}", e);
} }
} }

View File

@ -67,7 +67,7 @@ impl<T> BinaryConvertable for Option<T> where T: BinaryConvertable {
impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> { impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> {
fn size(&self) -> usize { fn size(&self) -> usize {
1usize + match *self { match *self {
Ok(_) => 0, Ok(_) => 0,
Err(ref e) => e.size(), Err(ref e) => e.size(),
} }
@ -75,17 +75,17 @@ impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> {
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> { fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self { match *self {
Ok(_) => Ok(()), Ok(_) => Err(BinaryConvertError),
Err(ref e) => Ok(try!(e.to_bytes(buffer, length_stack))), Err(ref e) => Ok(try!(e.to_bytes(buffer, length_stack))),
} }
} }
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> { fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
match buffer[0] { Ok(Err(try!(E::from_bytes(&buffer, length_stack))))
0 => Ok(Ok(())),
1 => Ok(Err(try!(E::from_bytes(&buffer[1..], length_stack)))),
_ => Err(BinaryConvertError)
} }
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(Ok(()))
} }
fn len_params() -> usize { fn len_params() -> usize {
@ -104,8 +104,8 @@ impl<R: BinaryConvertable, E: BinaryConvertable> BinaryConvertable for Result<R,
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> { fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self { match *self {
Ok(ref r) => Ok(try!(r.to_bytes(buffer, length_stack))), Ok(ref r) => { buffer[0] = 0; Ok(try!(r.to_bytes(&mut buffer[1..], length_stack))) },
Err(ref e) => Ok(try!(e.to_bytes(buffer, length_stack))), Err(ref e) => { buffer[1] = 1; Ok(try!(e.to_bytes(&mut buffer[1..], length_stack))) },
} }
} }
@ -297,29 +297,29 @@ pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError>
T::from_bytes(&payload_buffer[..], &mut fake_stack) T::from_bytes(&payload_buffer[..], &mut fake_stack)
}, },
_ => { _ => {
let mut length_stack = VecDeque::<usize>::new(); let mut payload = Vec::new();
let mut size_buffer = [0u8; 8]; try!(r.read_to_end(&mut payload).map_err(|_| BinaryConvertError));
try!(r.read(&mut size_buffer[..]).map_err(|_| BinaryConvertError));
let stack_len = try!(u64::from_bytes(&mut size_buffer[..], &mut fake_stack)) as usize;
if stack_len > 0 {
let mut header_buffer = Vec::with_capacity(stack_len * 8);
unsafe { header_buffer.set_len(stack_len * 8); };
try!(r.read(&mut header_buffer[..]).map_err(|_| BinaryConvertError)); let mut length_stack = VecDeque::<usize>::new();
let stack_len = try!(u64::from_bytes(&payload[0..8], &mut fake_stack)) as usize;
if stack_len > 0 {
for idx in 0..stack_len { for idx in 0..stack_len {
let stack_item = try!(u64::from_bytes(&header_buffer[idx*8..(idx+1)*8], &mut fake_stack)); let stack_item = try!(u64::from_bytes(&payload[8 + idx*8..8 + (idx+1)*8], &mut fake_stack));
length_stack.push_back(stack_item as usize); length_stack.push_back(stack_item as usize);
} }
} }
try!(r.read(&mut size_buffer[..]).map_err(|_| BinaryConvertError)); //try!(r.read(&mut size_buffer).map_err(|_| BinaryConvertError));
let size = try!(u64::from_bytes(&size_buffer[..], &mut fake_stack)) as usize; let size = try!(u64::from_bytes(&payload[8+stack_len*8..16+stack_len*8], &mut fake_stack)) as usize;
match size {
let mut data = Vec::with_capacity(size); 0 => {
unsafe { data.set_len(size) }; T::from_empty_bytes()
try!(r.read(&mut data).map_err(|_| BinaryConvertError)); },
_ => {
T::from_bytes(&data[..], &mut length_stack) T::from_bytes(&payload[16+stack_len*8..], &mut length_stack)
}
}
}, },
} }
} }
@ -350,6 +350,12 @@ pub fn serialize_into<T, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError>
let mut size_buffer = [0u8; 8]; let mut size_buffer = [0u8; 8];
let size = t.size(); let size = t.size();
if size == 0 {
try!(w.write(&size_buffer).map_err(|_| BinaryConvertError));
try!(w.write(&size_buffer).map_err(|_| BinaryConvertError));
return Ok(());
}
let mut buffer = Vec::with_capacity(size); let mut buffer = Vec::with_capacity(size);
unsafe { buffer.set_len(size); } unsafe { buffer.set_len(size); }
try!(t.to_bytes(&mut buffer[..], &mut length_stack)); try!(t.to_bytes(&mut buffer[..], &mut length_stack));
@ -386,7 +392,8 @@ pub fn serialize<T: BinaryConvertable>(t: &T) -> Result<Vec<u8>, BinaryConvertEr
use std::io::Cursor; use std::io::Cursor;
let mut buff = Cursor::new(Vec::new()); let mut buff = Cursor::new(Vec::new());
try!(serialize_into(t, &mut buff)); try!(serialize_into(t, &mut buff));
Ok(buff.into_inner()) let into_inner = buff.into_inner();
Ok(into_inner)
} }
#[macro_export] #[macro_export]
@ -544,7 +551,7 @@ fn deserialize_from_ok() {
fn serialize_into_deserialize_from() { fn serialize_into_deserialize_from() {
use std::io::{Cursor, SeekFrom, Seek}; use std::io::{Cursor, SeekFrom, Seek};
let mut buff = Cursor::new(vec![0u8; 1024]); let mut buff = Cursor::new(Vec::new());
let mut v = Vec::new(); let mut v = Vec::new();
v.push(Some(5u64)); v.push(Some(5u64));
v.push(None); v.push(None);
@ -557,3 +564,58 @@ fn serialize_into_deserialize_from() {
let de_v = deserialize_from::<Vec<Option<u64>>, _>(&mut buff).unwrap(); let de_v = deserialize_from::<Vec<Option<u64>>, _>(&mut buff).unwrap();
assert_eq!(v, de_v); assert_eq!(v, de_v);
} }
#[test]
fn serialize_opt_vec() {
use std::io::Cursor;
let mut buff = Cursor::new(Vec::new());
let optional_vec: Option<Vec<u8>> = None;
serialize_into(&optional_vec, &mut buff).unwrap();
assert_eq!(&vec![0u8; 16], buff.get_ref());
}
#[test]
fn serialize_opt_vec_payload() {
use std::io::Cursor;
let optional_vec: Option<Vec<u8>> = None;
let payload = serialize(&optional_vec).unwrap();
assert_eq!(vec![0u8;16], payload);
}
#[test]
fn deserialize_opt_vec() {
use std::io::Cursor;
let mut buff = Cursor::new(vec![0u8; 16]);
let vec = deserialize_from::<Option<Vec<u8>>, _>(&mut buff).unwrap();
assert!(vec.is_none());
}
#[test]
fn deserialize_simple_err() {
use std::io::Cursor;
let mut buff = Cursor::new(vec![0u8; 16]);
let result = deserialize_from::<Result<(), u32>, _>(&mut buff).unwrap();
assert!(result.is_ok());
}
#[test]
fn deserialize_opt_vec_in_out() {
use std::io::{Cursor, SeekFrom, Seek};
let mut buff = Cursor::new(Vec::new());
let optional_vec: Option<Vec<u8>> = None;
serialize_into(&optional_vec, &mut buff).unwrap();
buff.seek(SeekFrom::Start(0)).unwrap();
let vec = deserialize_from::<Option<Vec<u8>>, _>(&mut buff).unwrap();
assert!(vec.is_none());
}

View File

@ -42,3 +42,17 @@ pub enum EnumWithStruct {
Left, Left,
Right { how_much: u64 }, Right { how_much: u64 },
} }
#[derive(Binary)]
pub struct TwoVec {
v1: Vec<u8>,
v2: Vec<u8>,
}
#[test]
fn opt_two_vec() {
let example: Option<TwoVec> = None;
let serialized = ::ipc::binary::serialize(&example).unwrap();
assert_eq!(serialized, vec![0u8; 16]);
}

View File

@ -30,6 +30,7 @@ pub struct DB<L: Sized> {
pub trait DBWriter { pub trait DBWriter {
fn write(&self, data: Vec<u8>) -> Result<(), DBError>; fn write(&self, data: Vec<u8>) -> Result<(), DBError>;
fn write_slice(&self, data: &[u8]) -> Result<(), DBError>;
} }
impl<L: Sized> IpcConfig for DB<L> {} impl<L: Sized> IpcConfig for DB<L> {}
@ -44,5 +45,11 @@ impl<L: Sized> DBWriter for DB<L> {
*writes = *writes + data.len() as u64; *writes = *writes + data.len() as u64;
Ok(()) Ok(())
} }
fn write_slice(&self, data: &[u8]) -> Result<(), DBError> {
let mut writes = self.writes.write().unwrap();
*writes = *writes + data.len() as u64;
Ok(())
}
} }

View File

@ -20,7 +20,7 @@ use std::sync::atomic::AtomicBool;
use util::*; use util::*;
use util::keys::store::{AccountService, AccountProvider}; use util::keys::store::{AccountService, AccountProvider};
use ethcore::views::{BlockView, HeaderView}; use ethcore::views::{BlockView, HeaderView};
use ethcore::client::{BlockChainClient, BlockId}; use ethcore::client::{BlockChainClient, BlockID};
use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::block::{ClosedBlock, IsBlock};
use ethcore::error::*; use ethcore::error::*;
use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions}; use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions};
@ -475,7 +475,7 @@ impl MinerService for Miner {
fn chain_new_blocks(&self, chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { fn chain_new_blocks(&self, chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
let block = chain let block = chain
.block(BlockId::Hash(*hash)) .block(BlockID::Hash(*hash))
// Client should send message after commit to db and inserting to chain. // Client should send message after commit to db and inserting to chain.
.expect("Expected in-chain blocks."); .expect("Expected in-chain blocks.");
let block = BlockView::new(&block); let block = BlockView::new(&block);

View File

@ -16,6 +16,7 @@
use std; use std;
use ethcore; use ethcore;
use ethcore::client::Error as ClientError;
use util::UtilError; use util::UtilError;
use std::process::exit; use std::process::exit;
@ -29,6 +30,7 @@ pub fn die_with_error(module: &'static str, e: ethcore::error::Error) -> ! {
match e { match e {
Error::Util(UtilError::StdIo(e)) => die_with_io_error(module, e), Error::Util(UtilError::StdIo(e)) => die_with_io_error(module, e),
Error::Client(ClientError::Trace(e)) => die_with_message(&format!("{}", e)),
_ => die!("{}: {:?}", module, e), _ => die!("{}: {:?}", module, e),
} }
} }

View File

@ -28,7 +28,7 @@ use util::numbers::*;
use util::sha3::*; use util::sha3::*;
use util::bytes::{ToPretty}; use util::bytes::{ToPretty};
use util::rlp::{encode, decode, UntrustedRlp, View}; use util::rlp::{encode, decode, UntrustedRlp, View};
use ethcore::client::*; use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID};
use ethcore::block::IsBlock; use ethcore::block::IsBlock;
use ethcore::views::*; use ethcore::views::*;
use ethcore::ethereum::Ethash; use ethcore::ethereum::Ethash;
@ -75,7 +75,7 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
} }
} }
fn block(&self, id: BlockId, include_txs: bool) -> Result<Value, Error> { fn block(&self, id: BlockID, include_txs: bool) -> Result<Value, Error> {
let client = take_weak!(self.client); let client = take_weak!(self.client);
match (client.block(id.clone()), client.block_total_difficulty(id)) { match (client.block(id.clone()), client.block_total_difficulty(id)) {
(Some(bytes), Some(total_difficulty)) => { (Some(bytes), Some(total_difficulty)) => {
@ -114,16 +114,16 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
} }
} }
fn transaction(&self, id: TransactionId) -> Result<Value, Error> { fn transaction(&self, id: TransactionID) -> Result<Value, Error> {
match take_weak!(self.client).transaction(id) { match take_weak!(self.client).transaction(id) {
Some(t) => to_value(&Transaction::from(t)), Some(t) => to_value(&Transaction::from(t)),
None => Ok(Value::Null) None => Ok(Value::Null)
} }
} }
fn uncle(&self, id: UncleId) -> Result<Value, Error> { fn uncle(&self, id: UncleID) -> Result<Value, Error> {
let client = take_weak!(self.client); let client = take_weak!(self.client);
match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.parent_hash().clone())).map(|diff| (diff, u))) { match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockID::Hash(u.parent_hash().clone())).map(|diff| (diff, u))) {
Some((parent_difficulty, uncle)) => { Some((parent_difficulty, uncle)) => {
let block = Block { let block = Block {
hash: OptionalValue::Value(uncle.hash()), hash: OptionalValue::Value(uncle.hash()),
@ -233,8 +233,8 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
Params::None => { Params::None => {
let status = take_weak!(self.sync).status(); let status = take_weak!(self.sync).status();
let res = match status.state { let res = match status.state {
SyncState::NotSynced | SyncState::Idle => SyncStatus::None, SyncState::Idle => SyncStatus::None,
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => SyncStatus::Info(SyncInfo {
starting_block: U256::from(status.start_block_number), starting_block: U256::from(status.start_block_number),
current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), current_block: U256::from(take_weak!(self.client).chain_info().best_block_number),
highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number)) highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number))
@ -322,7 +322,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
fn block_transaction_count_by_hash(&self, params: Params) -> Result<Value, Error> { fn block_transaction_count_by_hash(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params) from_params::<(H256,)>(params)
.and_then(|(hash,)| // match .and_then(|(hash,)| // match
take_weak!(self.client).block(BlockId::Hash(hash)) take_weak!(self.client).block(BlockID::Hash(hash))
.map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count())))) .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count()))))
} }
@ -340,7 +340,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
fn block_uncles_count_by_hash(&self, params: Params) -> Result<Value, Error> { fn block_uncles_count_by_hash(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params) from_params::<(H256,)>(params)
.and_then(|(hash,)| .and_then(|(hash,)|
take_weak!(self.client).block(BlockId::Hash(hash)) take_weak!(self.client).block(BlockID::Hash(hash))
.map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count())))) .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count()))))
} }
@ -364,7 +364,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
fn block_by_hash(&self, params: Params) -> Result<Value, Error> { fn block_by_hash(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256, bool)>(params) from_params::<(H256, bool)>(params)
.and_then(|(hash, include_txs)| self.block(BlockId::Hash(hash), include_txs)) .and_then(|(hash, include_txs)| self.block(BlockID::Hash(hash), include_txs))
} }
fn block_by_number(&self, params: Params) -> Result<Value, Error> { fn block_by_number(&self, params: Params) -> Result<Value, Error> {
@ -378,38 +378,38 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
let miner = take_weak!(self.miner); let miner = take_weak!(self.miner);
match miner.transaction(&hash) { match miner.transaction(&hash) {
Some(pending_tx) => to_value(&Transaction::from(pending_tx)), Some(pending_tx) => to_value(&Transaction::from(pending_tx)),
None => self.transaction(TransactionId::Hash(hash)) None => self.transaction(TransactionID::Hash(hash))
} }
}) })
} }
fn transaction_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> { fn transaction_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256, Index)>(params) from_params::<(H256, Index)>(params)
.and_then(|(hash, index)| self.transaction(TransactionId::Location(BlockId::Hash(hash), index.value()))) .and_then(|(hash, index)| self.transaction(TransactionID::Location(BlockID::Hash(hash), index.value())))
} }
fn transaction_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> { fn transaction_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
from_params::<(BlockNumber, Index)>(params) from_params::<(BlockNumber, Index)>(params)
.and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) .and_then(|(number, index)| self.transaction(TransactionID::Location(number.into(), index.value())))
} }
fn transaction_receipt(&self, params: Params) -> Result<Value, Error> { fn transaction_receipt(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params) from_params::<(H256,)>(params)
.and_then(|(hash,)| { .and_then(|(hash,)| {
let client = take_weak!(self.client); let client = take_weak!(self.client);
let receipt = client.transaction_receipt(TransactionId::Hash(hash)); let receipt = client.transaction_receipt(TransactionID::Hash(hash));
to_value(&receipt.map(Receipt::from)) to_value(&receipt.map(Receipt::from))
}) })
} }
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> { fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256, Index)>(params) from_params::<(H256, Index)>(params)
.and_then(|(hash, index)| self.uncle(UncleId(BlockId::Hash(hash), index.value()))) .and_then(|(hash, index)| self.uncle(UncleID(BlockID::Hash(hash), index.value())))
} }
fn uncle_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> { fn uncle_by_block_number_and_index(&self, params: Params) -> Result<Value, Error> {
from_params::<(BlockNumber, Index)>(params) from_params::<(BlockNumber, Index)>(params)
.and_then(|(number, index)| self.uncle(UncleId(number.into(), index.value()))) .and_then(|(number, index)| self.uncle(UncleID(number.into(), index.value())))
} }
fn compilers(&self, params: Params) -> Result<Value, Error> { fn compilers(&self, params: Params) -> Result<Value, Error> {
@ -617,7 +617,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
// + 1, cause we want to return hashes including current block hash. // + 1, cause we want to return hashes including current block hash.
let current_number = client.chain_info().best_block_number + 1; let current_number = client.chain_info().best_block_number + 1;
let hashes = (*block_number..current_number).into_iter() let hashes = (*block_number..current_number).into_iter()
.map(BlockId::Number) .map(BlockID::Number)
.filter_map(|id| client.block_hash(id)) .filter_map(|id| client.block_hash(id))
.collect::<Vec<H256>>(); .collect::<Vec<H256>>();
@ -641,8 +641,8 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
}, },
PollFilter::Logs(ref mut block_number, ref filter) => { PollFilter::Logs(ref mut block_number, ref filter) => {
let mut filter = filter.clone(); let mut filter = filter.clone();
filter.from_block = BlockId::Number(*block_number); filter.from_block = BlockID::Number(*block_number);
filter.to_block = BlockId::Latest; filter.to_block = BlockID::Latest;
let logs = client.logs(filter) let logs = client.logs(filter)
.into_iter() .into_iter()
.map(From::from) .map(From::from)

View File

@ -19,7 +19,7 @@
use std::sync::{Weak, Arc}; use std::sync::{Weak, Arc};
use jsonrpc_core::*; use jsonrpc_core::*;
use util::H256; use util::H256;
use ethcore::client::{BlockChainClient, TransactionId, TraceId}; use ethcore::client::{BlockChainClient, TransactionID, TraceId};
use v1::traits::Traces; use v1::traits::Traces;
use v1::types::{TraceFilter, Trace, BlockNumber, Index}; use v1::types::{TraceFilter, Trace, BlockNumber, Index};
@ -62,7 +62,7 @@ impl<C> Traces for TracesClient<C> where C: BlockChainClient + 'static {
from_params::<(H256,)>(params) from_params::<(H256,)>(params)
.and_then(|(transaction_hash,)| { .and_then(|(transaction_hash,)| {
let client = take_weak!(self.client); let client = take_weak!(self.client);
let traces = client.transaction_traces(TransactionId::Hash(transaction_hash)); let traces = client.transaction_traces(TransactionID::Hash(transaction_hash));
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(Trace::from).collect()); let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(Trace::from).collect());
to_value(&traces) to_value(&traces)
}) })
@ -73,7 +73,7 @@ impl<C> Traces for TracesClient<C> where C: BlockChainClient + 'static {
.and_then(|(transaction_hash, address)| { .and_then(|(transaction_hash, address)| {
let client = take_weak!(self.client); let client = take_weak!(self.client);
let id = TraceId { let id = TraceId {
transaction: TransactionId::Hash(transaction_hash), transaction: TransactionID::Hash(transaction_hash),
address: address.into_iter().map(|i| i.value()).collect() address: address.into_iter().map(|i| i.value()).collect()
}; };
let trace = client.trace(id); let trace = client.trace(id);

View File

@ -21,7 +21,7 @@ use jsonrpc_core::IoHandler;
use util::hash::{Address, H256, FixedHash}; use util::hash::{Address, H256, FixedHash};
use util::numbers::{Uint, U256}; use util::numbers::{Uint, U256};
use util::keys::{TestAccount, TestAccountProvider}; use util::keys::{TestAccount, TestAccountProvider};
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID};
use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
use ethcore::receipt::LocalizedReceipt; use ethcore::receipt::LocalizedReceipt;
use ethcore::transaction::{Transaction, Action}; use ethcore::transaction::{Transaction, Action};
@ -562,7 +562,7 @@ fn rpc_eth_transaction_receipt() {
let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap(); let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap();
let tester = EthTester::default(); let tester = EthTester::default();
tester.client.set_transaction_receipt(TransactionId::Hash(hash), receipt); tester.client.set_transaction_receipt(TransactionID::Hash(hash), receipt);
let request = r#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",

View File

@ -39,7 +39,7 @@ impl TestSyncProvider {
pub fn new(config: Config) -> Self { pub fn new(config: Config) -> Self {
TestSyncProvider { TestSyncProvider {
status: RwLock::new(SyncStatus { status: RwLock::new(SyncStatus {
state: SyncState::NotSynced, state: SyncState::Idle,
network_id: config.network_id, network_id: config.network_id,
protocol_version: 63, protocol_version: 63,
start_block_number: 0, start_block_number: 0,

View File

@ -16,7 +16,7 @@
use serde::{Deserialize, Deserializer, Error}; use serde::{Deserialize, Deserializer, Error};
use serde::de::Visitor; use serde::de::Visitor;
use ethcore::client::BlockId; use ethcore::client::BlockID;
/// Represents rpc api block number param. /// Represents rpc api block number param.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -54,20 +54,20 @@ impl Visitor for BlockNumberVisitor {
} }
} }
impl Into<BlockId> for BlockNumber { impl Into<BlockID> for BlockNumber {
fn into(self) -> BlockId { fn into(self) -> BlockID {
match self { match self {
BlockNumber::Num(n) => BlockId::Number(n), BlockNumber::Num(n) => BlockID::Number(n),
BlockNumber::Earliest => BlockId::Earliest, BlockNumber::Earliest => BlockID::Earliest,
// TODO: change this once blockid support pendingst, // TODO: change this once blockid support pendingst,
BlockNumber::Pending | BlockNumber::Latest => BlockId::Latest, BlockNumber::Pending | BlockNumber::Latest => BlockID::Latest,
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ethcore::client::BlockId; use ethcore::client::BlockID;
use super::*; use super::*;
use serde_json; use serde_json;
@ -80,10 +80,10 @@ mod tests {
#[test] #[test]
fn block_number_into() { fn block_number_into() {
assert_eq!(BlockId::Number(100), BlockNumber::Num(100).into()); assert_eq!(BlockID::Number(100), BlockNumber::Num(100).into());
assert_eq!(BlockId::Earliest, BlockNumber::Earliest.into()); assert_eq!(BlockID::Earliest, BlockNumber::Earliest.into());
assert_eq!(BlockId::Latest, BlockNumber::Latest.into()); assert_eq!(BlockID::Latest, BlockNumber::Latest.into());
assert_eq!(BlockId::Latest, BlockNumber::Pending.into()); assert_eq!(BlockID::Latest, BlockNumber::Pending.into());
} }
} }

View File

@ -20,7 +20,7 @@ use jsonrpc_core::Value;
use util::numbers::*; use util::numbers::*;
use v1::types::BlockNumber; use v1::types::BlockNumber;
use ethcore::filter::Filter as EthFilter; use ethcore::filter::Filter as EthFilter;
use ethcore::client::BlockId; use ethcore::client::BlockID;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum VariadicValue<T> where T: Deserialize { pub enum VariadicValue<T> where T: Deserialize {
@ -61,8 +61,8 @@ pub struct Filter {
impl Into<EthFilter> for Filter { impl Into<EthFilter> for Filter {
fn into(self) -> EthFilter { fn into(self) -> EthFilter {
EthFilter { EthFilter {
from_block: self.from_block.map_or_else(|| BlockId::Latest, Into::into), from_block: self.from_block.map_or_else(|| BlockID::Latest, Into::into),
to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into), to_block: self.to_block.map_or_else(|| BlockID::Latest, Into::into),
address: self.address.and_then(|address| match address { address: self.address.and_then(|address| match address {
VariadicValue::Null => None, VariadicValue::Null => None,
VariadicValue::Single(a) => Some(vec![a]), VariadicValue::Single(a) => Some(vec![a]),

View File

@ -17,7 +17,7 @@
//! Trace filter deserialization. //! Trace filter deserialization.
use util::Address; use util::Address;
use ethcore::client::BlockId; use ethcore::client::BlockID;
use ethcore::client; use ethcore::client;
use super::BlockNumber; use super::BlockNumber;
@ -35,8 +35,8 @@ pub struct TraceFilter {
impl Into<client::TraceFilter> for TraceFilter { impl Into<client::TraceFilter> for TraceFilter {
fn into(self) -> client::TraceFilter { fn into(self) -> client::TraceFilter {
let start = self.from_block.map_or(BlockId::Latest, Into::into); let start = self.from_block.map_or(BlockID::Latest, Into::into);
let end = self.to_block.map_or(BlockId::Latest, Into::into); let end = self.to_block.map_or(BlockID::Latest, Into::into);
client::TraceFilter { client::TraceFilter {
range: start..end, range: start..end,
from_address: self.from_address.unwrap_or_else(Vec::new), from_address: self.from_address.unwrap_or_else(Vec::new),

View File

@ -307,7 +307,7 @@ impl BlockCollection {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::BlockCollection; use super::BlockCollection;
use ethcore::client::{TestBlockChainClient, EachBlockWith, BlockId, BlockChainClient}; use ethcore::client::{TestBlockChainClient, EachBlockWith, BlockID, BlockChainClient};
use ethcore::views::HeaderView; use ethcore::views::HeaderView;
use ethcore::header::BlockNumber; use ethcore::header::BlockNumber;
use util::*; use util::*;
@ -328,7 +328,7 @@ mod test {
assert!(is_empty(&bc)); assert!(is_empty(&bc));
let client = TestBlockChainClient::new(); let client = TestBlockChainClient::new();
client.add_blocks(100, EachBlockWith::Nothing); client.add_blocks(100, EachBlockWith::Nothing);
let hashes = (0 .. 100).map(|i| (&client as &BlockChainClient).block_hash(BlockId::Number(i)).unwrap()).collect(); let hashes = (0 .. 100).map(|i| (&client as &BlockChainClient).block_hash(BlockID::Number(i)).unwrap()).collect();
bc.reset_to(hashes); bc.reset_to(hashes);
assert!(!is_empty(&bc)); assert!(!is_empty(&bc));
bc.clear(); bc.clear();
@ -342,7 +342,7 @@ mod test {
let client = TestBlockChainClient::new(); let client = TestBlockChainClient::new();
let nblocks = 200; let nblocks = 200;
client.add_blocks(nblocks, EachBlockWith::Nothing); client.add_blocks(nblocks, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect(); let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockID::Number(i as BlockNumber)).unwrap()).collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect(); let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();
@ -395,7 +395,7 @@ mod test {
let client = TestBlockChainClient::new(); let client = TestBlockChainClient::new();
let nblocks = 200; let nblocks = 200;
client.add_blocks(nblocks, EachBlockWith::Nothing); client.add_blocks(nblocks, EachBlockWith::Nothing);
let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockId::Number(i as BlockNumber)).unwrap()).collect(); let blocks: Vec<_> = (0 .. nblocks).map(|i| (&client as &BlockChainClient).block(BlockID::Number(i as BlockNumber)).unwrap()).collect();
let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect(); let headers: Vec<_> = blocks.iter().map(|b| Rlp::new(b).at(0).as_raw().to_vec()).collect();
let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect(); let hashes: Vec<_> = headers.iter().map(|h| HeaderView::new(h).sha3()).collect();
let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect(); let heads: Vec<_> = hashes.iter().enumerate().filter_map(|(i, h)| if i % 20 == 0 { Some(h.clone()) } else { None }).collect();

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@
//! fn main() { //! fn main() {
//! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap();
//! let dir = env::temp_dir(); //! let dir = env::temp_dir();
//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap();
//! let miner = Miner::new(false, ethereum::new_frontier()); //! let miner = Miner::new(false, ethereum::new_frontier());
//! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! EthSync::register(&mut service, SyncConfig::default(), client, miner);
//! } //! }
@ -74,8 +74,8 @@ use io::NetSyncIo;
use chain::ChainSync; use chain::ChainSync;
mod chain; mod chain;
mod blocks;
mod io; mod io;
mod range_collection;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -116,9 +116,10 @@ pub use self::chain::{SyncStatus, SyncState};
impl EthSync { impl EthSync {
/// Creates and register protocol with the network service /// Creates and register protocol with the network service
pub fn register(service: &mut NetworkService<SyncMessage>, config: SyncConfig, chain: Arc<Client>, miner: Arc<Miner>) -> Arc<EthSync> { pub fn register(service: &mut NetworkService<SyncMessage>, config: SyncConfig, chain: Arc<Client>, miner: Arc<Miner>) -> Arc<EthSync> {
let sync = ChainSync::new(config, miner, chain.deref());
let sync = Arc::new(EthSync { let sync = Arc::new(EthSync {
chain: chain, chain: chain,
sync: RwLock::new(ChainSync::new(config, miner)), sync: RwLock::new(sync),
}); });
service.register_protocol(sync.clone(), "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler"); service.register_protocol(sync.clone(), "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler");
sync sync

View File

@ -1,317 +0,0 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// This module defines a trait for a collection of ranged values and an implementation
/// for this trait over sorted vector.
use std::ops::{Add, Sub, Range};
pub trait ToUsize {
fn to_usize(&self) -> usize;
}
pub trait FromUsize {
fn from_usize(s: usize) -> Self;
}
/// A key-value collection orderd by key with sequential key-value pairs grouped together.
/// Such group is called a range.
/// E.g. a set of collection of 5 pairs {1, a}, {2, b}, {10, x}, {11, y}, {12, z} will be grouped into two ranges: {1, [a,b]}, {10, [x,y,z]}
pub trait RangeCollection<K, V> {
/// Check if the given key is present in the collection.
fn have_item(&self, key: &K) -> bool;
/// Get value by key.
fn find_item(&self, key: &K) -> Option<&V>;
/// Get a range of keys from `key` till the end of the range that has `key`
/// Returns an empty range is key does not exist.
fn get_tail(&mut self, key: &K) -> Range<K>;
/// Remove all elements < `start` in the range that contains `start` - 1
fn remove_head(&mut self, start: &K);
/// Remove all elements >= `start` in the range that contains `start`
fn remove_tail(&mut self, start: &K);
/// Remove all elements >= `start`
fn remove_from(&mut self, start: &K);
/// Remove all elements >= `tail`
fn insert_item(&mut self, key: K, value: V);
/// Get an iterator over ranges
fn range_iter(& self) -> RangeIterator<K, V>;
}
/// Range iterator. For each range yelds a key for the first element of the range and a vector of values.
pub struct RangeIterator<'c, K:'c, V:'c> {
range: usize,
collection: &'c Vec<(K, Vec<V>)>
}
impl<'c, K:'c, V:'c> Iterator for RangeIterator<'c, K, V> where K: Add<Output = K> + FromUsize + ToUsize + Copy {
type Item = (K, &'c [V]);
// The 'Iterator' trait only requires the 'next' method to be defined. The
// return type is 'Option<T>', 'None' is returned when the 'Iterator' is
// over, otherwise the next value is returned wrapped in 'Some'
fn next(&mut self) -> Option<(K, &'c [V])> {
if self.range > 0 {
self.range -= 1;
}
else {
return None;
}
match self.collection.get(self.range) {
Some(&(ref k, ref vec)) => {
Some((*k, vec))
},
None => None
}
}
}
impl<K, V> RangeCollection<K, V> for Vec<(K, Vec<V>)> where K: Ord + PartialEq + Add<Output = K> + Sub<Output = K> + Copy + FromUsize + ToUsize {
fn range_iter(&self) -> RangeIterator<K, V> {
RangeIterator {
range: self.len(),
collection: self
}
}
fn have_item(&self, key: &K) -> bool {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(_) => true,
Err(index) => match self.get(index) {
Some(&(ref k, ref v)) => k <= key && (*k + FromUsize::from_usize(v.len())) > *key,
_ => false
},
}
}
fn find_item(&self, key: &K) -> Option<&V> {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => self.get(index).unwrap().1.get(0),
Err(index) => match self.get(index) {
Some(&(ref k, ref v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => v.get((*key - *k).to_usize()),
_ => None
},
}
}
fn get_tail(&mut self, key: &K) -> Range<K> {
let kv = *key;
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => kv..(kv + FromUsize::from_usize(self[index].1.len())),
Err(index) => {
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
kv..(*k + FromUsize::from_usize(v.len()))
}
_ => kv..kv
}
},
}
}
/// Remove element key and following elements in the same range
fn remove_tail(&mut self, key: &K) {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => { self.remove(index); },
Err(index) =>{
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
v.truncate((*key - *k).to_usize());
empty = v.is_empty();
}
_ => {}
}
if empty {
self.remove(index);
}
},
}
}
/// Remove the element and all following it.
fn remove_from(&mut self, key: &K) {
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(index) => { self.drain(.. index + 1); },
Err(index) =>{
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => {
v.truncate((*key - *k).to_usize());
empty = v.is_empty();
}
_ => {}
}
if empty {
self.drain(.. index + 1);
} else {
self.drain(.. index);
}
},
}
}
/// Remove range elements up to key
fn remove_head(&mut self, key: &K) {
if *key == FromUsize::from_usize(0) {
return
}
let prev = *key - FromUsize::from_usize(1);
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
Ok(_) => { }, //start of range, do nothing.
Err(index) => {
let mut empty = false;
match self.get_mut(index) {
Some(&mut (ref mut k, ref mut v)) if *k <= prev && (*k + FromUsize::from_usize(v.len())) > prev => {
let tail = v.split_off((*key - *k).to_usize());
empty = tail.is_empty();
let removed = ::std::mem::replace(v, tail);
let new_k = *k + FromUsize::from_usize(removed.len());
::std::mem::replace(k, new_k);
}
_ => {}
}
if empty {
self.remove(index);
}
},
}
}
fn insert_item(&mut self, key: K, value: V) {
assert!(!self.have_item(&key));
// todo: fix warning
let lower = match self.binary_search_by(|&(k, _)| k.cmp(&key).reverse()) {
Ok(index) | Err(index) => index
};
let mut to_remove: Option<usize> = None;
if lower < self.len() && self[lower].0 + FromUsize::from_usize(self[lower].1.len()) == key {
// extend into existing chunk
self[lower].1.push(value);
}
else {
// insert a new chunk
let range: Vec<V> = vec![value];
self.insert(lower, (key, range));
};
if lower > 0 {
let next = lower - 1;
if next < self.len()
{
{
let (mut next, mut inserted) = self.split_at_mut(lower);
let mut next = next.last_mut().unwrap();
let mut inserted = inserted.first_mut().unwrap();
if next.0 == key + FromUsize::from_usize(1)
{
inserted.1.append(&mut next.1);
to_remove = Some(lower - 1);
}
}
if let Some(r) = to_remove {
self.remove(r);
}
}
}
}
}
#[test]
#[cfg_attr(feature="dev", allow(cyclomatic_complexity))]
fn test_range() {
use std::cmp::{Ordering};
let mut ranges: Vec<(u64, Vec<char>)> = Vec::new();
assert_eq!(ranges.range_iter().next(), None);
assert_eq!(ranges.find_item(&1), None);
assert!(!ranges.have_item(&1));
assert_eq!(ranges.get_tail(&0), 0..0);
ranges.insert_item(17, 'q');
assert_eq!(ranges.range_iter().cmp(vec![(17, &['q'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&17), Some(&'q'));
assert!(ranges.have_item(&17));
assert_eq!(ranges.get_tail(&17), 17..18);
ranges.insert_item(18, 'r');
assert_eq!(ranges.range_iter().cmp(vec![(17, &['q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&18), Some(&'r'));
assert!(ranges.have_item(&18));
assert_eq!(ranges.get_tail(&17), 17..19);
ranges.insert_item(16, 'p');
assert_eq!(ranges.range_iter().cmp(vec![(16, &['p', 'q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&16), Some(&'p'));
assert_eq!(ranges.find_item(&17), Some(&'q'));
assert_eq!(ranges.find_item(&18), Some(&'r'));
assert!(ranges.have_item(&16));
assert_eq!(ranges.get_tail(&17), 17..19);
assert_eq!(ranges.get_tail(&16), 16..19);
ranges.insert_item(2, 'b');
assert_eq!(ranges.range_iter().cmp(vec![(2, &['b'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
assert_eq!(ranges.find_item(&2), Some(&'b'));
ranges.insert_item(3, 'c');
ranges.insert_item(4, 'd');
assert_eq!(ranges.get_tail(&3), 3..5);
assert_eq!(ranges.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
let mut r = ranges.clone();
r.remove_head(&1);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&2);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&3);
assert_eq!(r.range_iter().cmp(vec![(3, &['c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&10);
assert_eq!(r.range_iter().cmp(vec![(3, &['c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&5);
assert_eq!(r.range_iter().cmp(vec![(16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_head(&19);
assert_eq!(r.range_iter().next(), None);
let mut r = ranges.clone();
r.remove_tail(&20);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_tail(&17);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p'][..])]), Ordering::Equal);
r.remove_tail(&16);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal);
r.remove_tail(&3);
assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal);
r.remove_tail(&2);
assert_eq!(r.range_iter().next(), None);
let mut r = ranges.clone();
r.remove_from(&20);
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal);
r.remove_from(&18);
assert!(!r.have_item(&18));
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q'][..])]), Ordering::Equal);
r.remove_from(&16);
assert!(!r.have_item(&16));
assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal);
r.remove_from(&3);
assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal);
r.remove_from(&1);
assert_eq!(r.range_iter().next(), None);
let mut r = ranges.clone();
r.remove_from(&2);
assert_eq!(r.range_iter().next(), None);
}

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::*; use util::*;
use ethcore::client::{BlockChainClient, BlockId, EachBlockWith}; use ethcore::client::{BlockChainClient, BlockID, EachBlockWith};
use chain::{SyncState}; use chain::{SyncState};
use super::helpers::*; use super::helpers::*;
@ -26,7 +26,17 @@ fn two_peers() {
net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle);
net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle);
net.sync(); net.sync();
assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref());
}
#[test]
fn long_chain() {
::env_logger::init().ok();
let mut net = TestNet::new(2);
net.peer_mut(1).chain.add_blocks(50000, EachBlockWith::Nothing);
net.sync();
assert!(net.peer(0).chain.block(BlockID::Number(50000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref());
} }
@ -47,7 +57,7 @@ fn takes_few_steps() {
net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle);
net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle); net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle);
let total_steps = net.sync(); let total_steps = net.sync();
assert!(total_steps < 7); assert!(total_steps < 20);
} }
#[test] #[test]
@ -60,7 +70,7 @@ fn empty_blocks() {
net.peer_mut(2).chain.add_blocks(5, with); net.peer_mut(2).chain.add_blocks(5, with);
} }
net.sync(); net.sync();
assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some());
assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref());
} }
@ -79,6 +89,7 @@ fn forked() {
// peer 1 has the best chain of 601 blocks // peer 1 has the best chain of 601 blocks
let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone();
net.sync(); net.sync();
assert_eq!(net.peer(0).chain.difficulty.read().unwrap().deref(), net.peer(1).chain.difficulty.read().unwrap().deref());
assert_eq!(net.peer(0).chain.numbers.read().unwrap().deref(), &peer1_chain); assert_eq!(net.peer(0).chain.numbers.read().unwrap().deref(), &peer1_chain);
assert_eq!(net.peer(1).chain.numbers.read().unwrap().deref(), &peer1_chain); assert_eq!(net.peer(1).chain.numbers.read().unwrap().deref(), &peer1_chain);
assert_eq!(net.peer(2).chain.numbers.read().unwrap().deref(), &peer1_chain); assert_eq!(net.peer(2).chain.numbers.read().unwrap().deref(), &peer1_chain);
@ -97,13 +108,13 @@ fn restart() {
net.restart_peer(0); net.restart_peer(0);
let status = net.peer(0).sync.status(); let status = net.peer(0).sync.status();
assert_eq!(status.state, SyncState::NotSynced); assert_eq!(status.state, SyncState::ChainHead);
} }
#[test] #[test]
fn status_empty() { fn status_empty() {
let net = TestNet::new(2); let net = TestNet::new(2);
assert_eq!(net.peer(0).sync.status().state, SyncState::NotSynced); assert_eq!(net.peer(0).sync.status().state, SyncState::Idle);
} }
#[test] #[test]
@ -166,8 +177,17 @@ fn restart_on_malformed_block() {
let mut net = TestNet::new(2); let mut net = TestNet::new(2);
net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle);
net.peer_mut(1).chain.corrupt_block(6); net.peer_mut(1).chain.corrupt_block(6);
net.sync_steps(10); net.sync_steps(20);
assert_eq!(net.peer(0).chain.chain_info().best_block_number, 4); assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5);
} }
#[test]
fn restart_on_broken_chain() {
let mut net = TestNet::new(2);
net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle);
net.peer_mut(1).chain.corrupt_block_parent(6);
net.sync_steps(20);
assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5);
}

View File

@ -92,9 +92,11 @@ impl TestNet {
started: false, started: false,
}; };
for _ in 0..n { for _ in 0..n {
let chain = TestBlockChainClient::new();
let sync = ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test()), &chain);
net.peers.push(TestPeer { net.peers.push(TestPeer {
chain: TestBlockChainClient::new(), sync: sync,
sync: ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test())), chain: chain,
queue: VecDeque::new(), queue: VecDeque::new(),
}); });
} }

View File

@ -17,7 +17,7 @@ nix ="0.5.0"
rand = "0.3.12" rand = "0.3.12"
time = "0.1.34" time = "0.1.34"
tiny-keccak = "1.0" tiny-keccak = "1.0"
rocksdb = { git = "https://github.com/arkpar/rust-rocksdb.git" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
lazy_static = "0.1" lazy_static = "0.1"
eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" } eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" }
rust-crypto = "0.2.34" rust-crypto = "0.2.34"

View File

@ -55,11 +55,11 @@ pub struct DatabaseConfig {
} }
/// Database iterator /// Database iterator
pub struct DatabaseIterator<'a> { pub struct DatabaseIterator {
iter: DBIterator<'a>, iter: DBIterator,
} }
impl<'a> Iterator for DatabaseIterator<'a> { impl<'a> Iterator for DatabaseIterator {
type Item = (Box<[u8]>, Box<[u8]>); type Item = (Box<[u8]>, Box<[u8]>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -135,7 +135,7 @@ impl Database {
/// Get value by partial key. Prefix size should match configured prefix size. /// Get value by partial key. Prefix size should match configured prefix size.
pub fn get_by_prefix(&self, prefix: &[u8]) -> Option<Box<[u8]>> { pub fn get_by_prefix(&self, prefix: &[u8]) -> Option<Box<[u8]>> {
let mut iter = self.db.iterator(IteratorMode::From(prefix, Direction::forward)); let mut iter = self.db.iterator(IteratorMode::From(prefix, Direction::Forward));
match iter.next() { match iter.next() {
// TODO: use prefix_same_as_start read option (not availabele in C API currently) // TODO: use prefix_same_as_start read option (not availabele in C API currently)
Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None }, Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None },