propagate trace error to the top

This commit is contained in:
debris 2016-05-18 11:34:15 +02:00
parent dcc695dda5
commit 14b6b389f2
12 changed files with 120 additions and 30 deletions

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;
@ -38,6 +38,7 @@ 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;
@ -99,7 +100,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)
} }
} }
@ -123,11 +124,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);
@ -141,7 +142,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,
@ -151,7 +152,9 @@ impl<V> Client<V> where V: Verifier {
import_lock: Mutex::new(()), import_lock: Mutex::new(()),
panic_handler: panic_handler, panic_handler: panic_handler,
verifier: PhantomData, verifier: PhantomData,
}) };
Ok(Arc::new(client))
} }
/// Flush the block import queue. /// Flush the block import queue.

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}; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch};
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;

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

@ -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

@ -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");
@ -56,7 +56,7 @@ fn imports_good_block() {
#[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());

View File

@ -145,7 +145,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;
@ -211,7 +211,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::{FixedHash, H256, H264, Database, DBTransaction}; use util::{FixedHash, 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,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 <http://www.gnu.org/licenses/>.
//! 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)
}
}

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

@ -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, UntrustedRlp, View}; use util::rlp::{encode, 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;