diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 0d61325d9..041dfd92a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use util::*; use util::panics::*; use views::BlockView; -use error::*; +use error::{Error, ImportError, ExecutionError, BlockError, ImportResult}; use header::{BlockNumber, Header}; use state::State; use spec::Spec; @@ -38,6 +38,7 @@ use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter}; +use client::Error as ClientError; use env_info::EnvInfo; use executive::{Executive, Executed, TransactOptions, contract_address}; use receipt::LocalizedReceipt; @@ -99,7 +100,7 @@ const CLIENT_DB_VER_STR: &'static str = "5.3"; impl Client { /// Create a new client with given spec and DB path. - pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Arc { + pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, ClientError> { Client::::new_with_verifier(config, spec, path, message_channel) } } @@ -123,11 +124,11 @@ pub fn append_path(path: &Path, item: &str) -> String { impl Client where V: 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 ) -> Arc> { + pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result>, ClientError> { let path = get_db_path(path, config.pruning, spec.genesis_header().hash()); let gb = spec.genesis_block(); 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); @@ -141,7 +142,7 @@ impl Client where V: Verifier { let panic_handler = PanicHandler::new_in_arc(); panic_handler.forward_from(&block_queue); - Arc::new(Client { + let client = Client { chain: chain, tracedb: tracedb, engine: engine, @@ -151,7 +152,9 @@ impl Client where V: Verifier { import_lock: Mutex::new(()), panic_handler: panic_handler, verifier: PhantomData, - }) + }; + + Ok(Arc::new(client)) } /// Flush the block import queue. diff --git a/ethcore/src/client/error.rs b/ethcore/src/client/error.rs new file mode 100644 index 000000000..fde22cb10 --- /dev/null +++ b/ethcore/src/client/error.rs @@ -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 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) + } + } +} diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index a748ff900..28237a3c1 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -18,11 +18,13 @@ mod client; mod config; +mod error; mod test_client; mod trace; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch}; +pub use self::error::Error; pub use types::ids::*; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::trace::Filter as TraceFilter; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index edec7c959..110d37a0b 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -19,6 +19,7 @@ use util::*; use header::BlockNumber; use basic_types::LogBloom; +use client::Error as ClientError; pub use types::executed::ExecutionError; @@ -134,6 +135,8 @@ pub enum ImportError { #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { + /// Client configuration error. + Client(ClientError), /// Error concerning a utility. Util(UtilError), /// Error concerning block processing. @@ -155,6 +158,12 @@ pub enum Error { /// Result of import block operation. pub type ImportResult = Result; +impl From for Error { + fn from(err: ClientError) -> Error { + Error::Client(err) + } +} + impl From for Error { fn from(err: TransactionError) -> Error { Error::Transaction(err) diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 2464b7cc6..38bd873b8 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -61,7 +61,7 @@ impl ClientService { info!("Starting {}", net_service.host_info()); 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()); let client_io = Arc::new(ClientIoHandler { client: client.clone() diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 926009ac4..25531692b 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -23,7 +23,7 @@ use devtools::*; #[test] fn imports_from_empty() { 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.flush_queue(); } @@ -41,7 +41,7 @@ fn returns_state_root_basic() { #[test] fn imports_good_block() { 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(); if let Err(_) = client.import_block(good_block) { panic!("error importing block being good by definition"); @@ -56,7 +56,7 @@ fn imports_good_block() { #[test] fn query_none_block() { 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)); assert!(non_existant.is_none()); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 56e33d76b..152ac0ef6 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -145,7 +145,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { 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_engine = &test_spec.engine; let state_root = test_spec.genesis_header().state_root; @@ -211,7 +211,7 @@ pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { 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 { if let Err(_) = client.import_block(block.clone()) { panic!("panic importing block which is well-formed"); diff --git a/ethcore/src/trace/config.rs b/ethcore/src/trace/config.rs index 3390fb2aa..76c62b43d 100644 --- a/ethcore/src/trace/config.rs +++ b/ethcore/src/trace/config.rs @@ -16,6 +16,7 @@ //! Traces config. use bloomchain::Config as BloomConfig; +use trace::Error; /// 3-value enum. #[derive(Debug, Clone, Copy, PartialEq)] @@ -30,10 +31,10 @@ pub enum Switch { impl Switch { /// Tries to turn old switch to new value. - pub fn turn_to(&self, to: Switch) -> Result { + pub fn turn_to(&self, to: Switch) -> Result { match (*self, to) { (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), } } diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index 5c88ee52b..bf78ef7c5 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -25,7 +25,7 @@ use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, Bloo use util::{FixedHash, H256, H264, Database, DBTransaction}; use header::BlockNumber; use trace::{BlockTraces, LocalizedTrace, Config, Switch, Filter, Database as TraceDatabase, ImportRequest, -DatabaseExtras}; +DatabaseExtras, Error}; use db::{Key, Writable, Readable, CacheUpdatePolicy}; use super::bloom::{TraceGroupPosition, BlockTracesBloom, BlockTracesBloomGroup}; use super::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces}; @@ -103,7 +103,7 @@ impl BloomGroupDatabase for TraceDB where T: DatabaseExtras { impl TraceDB where T: DatabaseExtras { /// Creates new instance of `TraceDB`. - pub fn new(config: Config, path: &Path, extras: Arc) -> Self { + pub fn new(config: Config, path: &Path, extras: Arc) -> Result { let mut tracedb_path = path.to_path_buf(); tracedb_path.push("tracedb"); let tracesdb = Database::open_default(tracedb_path.to_str().unwrap()).unwrap(); @@ -116,7 +116,7 @@ impl TraceDB where T: DatabaseExtras { 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 { true => [0x1], @@ -126,14 +126,16 @@ impl TraceDB where T: DatabaseExtras { tracesdb.put(b"enabled", &encoded_tracing).unwrap(); tracesdb.put(b"version", TRACE_DB_VER).unwrap(); - TraceDB { + let db = TraceDB { traces: RwLock::new(HashMap::new()), blooms: RwLock::new(HashMap::new()), tracesdb: tracesdb, bloom_config: config.blooms, enabled: enabled, extras: extras, - } + }; + + Ok(db) } /// Returns traces for block with hash. @@ -401,19 +403,19 @@ mod tests { 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); } { - 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); } 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); } } @@ -427,26 +429,26 @@ mod tests { 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); } { - 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); } 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); } 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); } } @@ -461,12 +463,12 @@ mod tests { 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); } 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 { @@ -526,7 +528,7 @@ mod tests { extras.transaction_hashes.insert(0, vec![tx_0.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 let request = create_simple_import_request(0, block_0.clone()); diff --git a/ethcore/src/trace/error.rs b/ethcore/src/trace/error.rs new file mode 100644 index 000000000..0f3cbc62c --- /dev/null +++ b/ethcore/src/trace/error.rs @@ -0,0 +1,48 @@ +// 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 . + +//! TraceDB errors. + +use std::fmt::{Debug, 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. +pub enum Error { + /// Returned when tracing is enabled, + /// but database does not contain traces of old transactions. + ResyncRequired, +} + +/// TODO: replace `Debug` with default implementation, +/// once we stop using it to display errors to user. +impl Debug for Error { + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + write!(f, "{}", RESYNC_ERR) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + write!(f, "{}", RESYNC_ERR) + } +} diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 01763a167..f51cf8ee5 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -20,6 +20,7 @@ mod block; mod bloom; mod config; mod db; +mod error; mod executive_tracer; pub mod flat; mod import; @@ -29,6 +30,7 @@ pub use types::trace_types::*; pub use self::block::BlockTraces; pub use self::config::{Config, Switch}; pub use self::db::TraceDB; +pub use self::error::Error; pub use types::trace_types::trace::Trace; pub use self::noop_tracer::NoopTracer; pub use self::executive_tracer::ExecutiveTracer; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 6fddf7b4f..8a12bbf61 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -28,7 +28,7 @@ use util::numbers::*; use util::sha3::*; use util::bytes::{ToPretty}; use util::rlp::{encode, UntrustedRlp, View}; -use ethcore::client::*; +use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId}; use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash;