Traces error handling (#4849)

This commit is contained in:
Tomasz Drwięga 2017-03-14 13:04:32 +01:00 committed by Gav Wood
parent 7c45178076
commit 2dca24cc28
12 changed files with 188 additions and 165 deletions

View File

@ -14,7 +14,6 @@
// 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 trace::Error as TraceError;
use util::UtilError; use util::UtilError;
use std::fmt::{Display, Formatter, Error as FmtError}; use std::fmt::{Display, Formatter, Error as FmtError};
@ -23,8 +22,6 @@ use util::trie::TrieError;
/// Client configuration errors. /// Client configuration errors.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// TraceDB configuration error.
Trace(TraceError),
/// TrieDB-related error. /// TrieDB-related error.
Trie(TrieError), Trie(TrieError),
/// Database error /// Database error
@ -33,12 +30,6 @@ pub enum Error {
Util(UtilError), Util(UtilError),
} }
impl From<TraceError> for Error {
fn from(err: TraceError) -> Self {
Error::Trace(err)
}
}
impl From<TrieError> for Error { impl From<TrieError> for Error {
fn from(err: TrieError) -> Self { fn from(err: TrieError) -> Self {
Error::Trie(err) Error::Trie(err)
@ -60,7 +51,6 @@ impl<E> From<Box<E>> for Error where Error: From<E> {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self { match *self {
Error::Trace(ref err) => write!(f, "{}", err),
Error::Trie(ref err) => write!(f, "{}", err), Error::Trie(ref err) => write!(f, "{}", err),
Error::Util(ref err) => write!(f, "{}", err), Error::Util(ref err) => write!(f, "{}", err),
Error::Database(ref s) => write!(f, "Database error: {}", s), Error::Database(ref s) => write!(f, "Database error: {}", s),

View File

@ -1,41 +0,0 @@
// Copyright 2015-2017 Parity Technologies (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

@ -19,7 +19,6 @@
mod bloom; mod bloom;
mod config; mod config;
mod db; mod db;
mod error;
mod executive_tracer; mod executive_tracer;
mod import; mod import;
mod noop_tracer; mod noop_tracer;
@ -28,7 +27,6 @@ pub use types::trace_types::{filter, flat, localized, trace};
pub use types::trace_types::error::Error as TraceError; pub use types::trace_types::error::Error as TraceError;
pub use self::config::Config; pub use self::config::Config;
pub use self::db::TraceDB; pub use self::db::TraceDB;
pub use self::error::Error;
pub use types::trace_types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff}; pub use types::trace_types::trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
pub use types::trace_types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces}; pub use types::trace_types::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::noop_tracer::{NoopTracer, NoopVMTracer}; pub use self::noop_tracer::{NoopTracer, NoopVMTracer};

View File

@ -32,7 +32,6 @@ mod codes {
pub const NO_WORK: i64 = -32001; pub const NO_WORK: i64 = -32001;
pub const NO_AUTHOR: i64 = -32002; pub const NO_AUTHOR: i64 = -32002;
pub const NO_NEW_WORK: i64 = -32003; pub const NO_NEW_WORK: i64 = -32003;
pub const NOT_ENOUGH_DATA: i64 = -32006;
pub const UNKNOWN_ERROR: i64 = -32009; pub const UNKNOWN_ERROR: i64 = -32009;
pub const TRANSACTION_ERROR: i64 = -32010; pub const TRANSACTION_ERROR: i64 = -32010;
pub const EXECUTION_ERROR: i64 = -32015; pub const EXECUTION_ERROR: i64 = -32015;
@ -41,9 +40,6 @@ mod codes {
pub const ACCOUNT_LOCKED: i64 = -32020; pub const ACCOUNT_LOCKED: i64 = -32020;
pub const PASSWORD_INVALID: i64 = -32021; pub const PASSWORD_INVALID: i64 = -32021;
pub const ACCOUNT_ERROR: i64 = -32023; pub const ACCOUNT_ERROR: i64 = -32023;
pub const SIGNER_DISABLED: i64 = -32030;
pub const DAPPS_DISABLED: i64 = -32031;
pub const NETWORK_DISABLED: i64 = -32035;
pub const REQUEST_REJECTED: i64 = -32040; pub const REQUEST_REJECTED: i64 = -32040;
pub const REQUEST_REJECTED_LIMIT: i64 = -32041; pub const REQUEST_REJECTED_LIMIT: i64 = -32041;
pub const REQUEST_NOT_FOUND: i64 = -32042; pub const REQUEST_NOT_FOUND: i64 = -32042;
@ -174,9 +170,9 @@ pub fn no_author() -> Error {
pub fn not_enough_data() -> Error { pub fn not_enough_data() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::NOT_ENOUGH_DATA), code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "The node does not have enough data to compute the given statistic.".into(), message: "The node does not have enough data to compute the given statistic.".into(),
data: None data: None,
} }
} }
@ -190,25 +186,25 @@ pub fn token(e: String) -> Error {
pub fn signer_disabled() -> Error { pub fn signer_disabled() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::SIGNER_DISABLED), code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Trusted Signer is disabled. This API is not available.".into(), message: "Trusted Signer is disabled. This API is not available.".into(),
data: None data: None,
} }
} }
pub fn dapps_disabled() -> Error { pub fn dapps_disabled() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::DAPPS_DISABLED), code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Dapps Server is disabled. This API is not available.".into(), message: "Dapps Server is disabled. This API is not available.".into(),
data: None data: None,
} }
} }
pub fn network_disabled() -> Error { pub fn network_disabled() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::NETWORK_DISABLED), code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Network is disabled or not yet up.".into(), message: "Network is disabled or not yet up.".into(),
data: None data: None,
} }
} }
@ -321,7 +317,7 @@ pub fn from_call_error(error: CallError) -> Error {
pub fn unknown_block() -> Error { pub fn unknown_block() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), code: ErrorCode::InvalidParams,
message: "Unknown block number".into(), message: "Unknown block number".into(),
data: None, data: None,
} }

View File

@ -0,0 +1,43 @@
// Copyright 2015-2017 Parity Technologies (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/>.
use std::sync::Weak;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
use ethcore::transaction::{Transaction, SignedTransaction, Action};
use jsonrpc_core::Error;
use v1::helpers::CallRequest;
use v1::helpers::dispatch::default_gas_price;
pub fn sign_call<B: MiningBlockChainClient, M: MinerService>(
client: &Weak<B>,
miner: &Weak<M>,
request: CallRequest,
) -> Result<SignedTransaction, Error> {
let client = take_weak!(client);
let miner = take_weak!(miner);
let from = request.from.unwrap_or(0.into());
Ok(Transaction {
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or(50_000_000.into()),
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&*client, &*miner)),
value: request.value.unwrap_or(0.into()),
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
}.fake_sign(from))
}

View File

@ -19,6 +19,7 @@ pub mod errors;
pub mod block_import; pub mod block_import;
pub mod dispatch; pub mod dispatch;
pub mod fake_sign;
pub mod informant; pub mod informant;
mod network_settings; mod network_settings;

View File

@ -23,7 +23,7 @@ use std::sync::{Arc, Weak};
use futures::{self, future, BoxFuture, Future}; use futures::{self, future, BoxFuture, Future};
use rlp::{self, UntrustedRlp, View}; use rlp::{self, UntrustedRlp, View};
use time::get_time; use time::get_time;
use util::{H160, H256, Address, U256, H64, Uint}; use util::{H160, H256, Address, U256, H64};
use util::sha3::Hashable; use util::sha3::Hashable;
use util::Mutex; use util::Mutex;
@ -36,14 +36,14 @@ use ethcore::filter::Filter as EthcoreFilter;
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber}; use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
use ethcore::log_entry::LogEntry; use ethcore::log_entry::LogEntry;
use ethcore::miner::{MinerService, ExternalMinerService}; use ethcore::miner::{MinerService, ExternalMinerService};
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use ethcore::transaction::SignedTransaction;
use ethcore::snapshot::SnapshotService; use ethcore::snapshot::SnapshotService;
use ethsync::{SyncProvider}; use ethsync::{SyncProvider};
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::helpers::{CallRequest as CRequest, errors, limit_logs}; use v1::helpers::{errors, limit_logs, fake_sign};
use v1::helpers::dispatch::{Dispatcher, FullDispatcher, default_gas_price}; use v1::helpers::dispatch::{Dispatcher, FullDispatcher, default_gas_price};
use v1::helpers::block_import::is_major_importing; use v1::helpers::block_import::is_major_importing;
use v1::traits::Eth; use v1::traits::Eth;
@ -222,19 +222,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
Ok(Some(block)) Ok(Some(block))
} }
fn sign_call(&self, request: CRequest) -> Result<SignedTransaction, Error> {
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
let from = request.from.unwrap_or(Address::zero());
Ok(EthTransaction {
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or(U256::from(50_000_000)),
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&*client, &*miner)),
value: request.value.unwrap_or_else(U256::zero),
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
}.fake_sign(from))
}
fn dapp_accounts(&self, dapp: DappId) -> Result<Vec<H160>, Error> { fn dapp_accounts(&self, dapp: DappId) -> Result<Vec<H160>, Error> {
let store = take_weak!(self.accounts); let store = take_weak!(self.accounts);
store store
@ -654,7 +641,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> { fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
let request = CallRequest::into(request); let request = CallRequest::into(request);
let signed = match self.sign_call(request) { let signed = match fake_sign::sign_call(&self.client, &self.miner, request) {
Ok(signed) => signed, Ok(signed) => signed,
Err(e) => return future::err(e).boxed(), Err(e) => return future::err(e).boxed(),
}; };
@ -672,7 +659,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn estimate_gas(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> { fn estimate_gas(&self, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
let request = CallRequest::into(request); let request = CallRequest::into(request);
let signed = match self.sign_call(request) { let signed = match fake_sign::sign_call(&self.client, &self.miner, request) {
Ok(signed) => signed, Ok(signed) => signed,
Err(e) => return future::err(e).boxed(), Err(e) => return future::err(e).boxed(),
}; };

View File

@ -27,15 +27,15 @@ use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, By
pub struct TracesClient; pub struct TracesClient;
impl Traces for TracesClient { impl Traces for TracesClient {
fn filter(&self, _filter: TraceFilter) -> Result<Vec<LocalizedTrace>, Error> { fn filter(&self, _filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn block_traces(&self, _block_number: BlockNumber) -> Result<Vec<LocalizedTrace>, Error> { fn block_traces(&self, _block_number: BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn transaction_traces(&self, _transaction_hash: H256) -> Result<Vec<LocalizedTrace>, Error> { fn transaction_traces(&self, _transaction_hash: H256) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
@ -43,15 +43,15 @@ impl Traces for TracesClient {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn call(&self, _request: CallRequest, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> { fn call(&self, _request: CallRequest, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> { fn raw_transaction(&self, _raw_transaction: Bytes, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
fn replay_transaction(&self, _transaction_hash: H256, _flags: Vec<String>) -> Result<Option<TraceResults>, Error> { fn replay_transaction(&self, _transaction_hash: H256, _flags: Vec<String>) -> Result<TraceResults, Error> {
Err(errors::light_unimplemented(None)) Err(errors::light_unimplemented(None))
} }
} }

View File

@ -19,14 +19,14 @@
use std::sync::{Weak, Arc}; use std::sync::{Weak, Arc};
use rlp::{UntrustedRlp, View}; use rlp::{UntrustedRlp, View};
use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId}; use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId};
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use ethcore::transaction::SignedTransaction;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use v1::traits::Traces; use v1::traits::Traces;
use v1::helpers::{errors, CallRequest as CRequest}; use v1::helpers::{errors, fake_sign};
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256}; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics { fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
@ -38,12 +38,12 @@ fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
} }
/// Traces api implementation. /// Traces api implementation.
pub struct TracesClient<C, M> where C: BlockChainClient, M: MinerService { pub struct TracesClient<C, M> {
client: Weak<C>, client: Weak<C>,
miner: Weak<M>, miner: Weak<M>,
} }
impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService { impl<C, M> TracesClient<C, M> {
/// Creates new Traces client. /// Creates new Traces client.
pub fn new(client: &Arc<C>, miner: &Arc<M>) -> Self { pub fn new(client: &Arc<C>, miner: &Arc<M>) -> Self {
TracesClient { TracesClient {
@ -51,86 +51,59 @@ impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService {
miner: Arc::downgrade(miner), miner: Arc::downgrade(miner),
} }
} }
// TODO: share with eth.rs
fn sign_call(&self, request: CRequest) -> Result<SignedTransaction, Error> {
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
let from = request.from.unwrap_or(0.into());
Ok(EthTransaction {
nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)),
action: request.to.map_or(Action::Create, Action::Call),
gas: request.gas.unwrap_or(50_000_000.into()),
gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()),
value: request.value.unwrap_or(0.into()),
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
}.fake_sign(from))
}
} }
impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M: MinerService + 'static { impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'static, M: MinerService + 'static {
fn filter(&self, filter: TraceFilter) -> Result<Vec<LocalizedTrace>, Error> { fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
let client = take_weak!(self.client); Ok(take_weak!(self.client).filter_traces(filter.into())
let traces = client.filter_traces(filter.into()); .map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
Ok(traces)
} }
fn block_traces(&self, block_number: BlockNumber) -> Result<Vec<LocalizedTrace>, Error> { fn block_traces(&self, block_number: BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error> {
let client = take_weak!(self.client); Ok(take_weak!(self.client).block_traces(block_number.into())
let traces = client.block_traces(block_number.into()); .map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
Ok(traces)
} }
fn transaction_traces(&self, transaction_hash: H256) -> Result<Vec<LocalizedTrace>, Error> { fn transaction_traces(&self, transaction_hash: H256) -> Result<Option<Vec<LocalizedTrace>>, Error> {
let client = take_weak!(self.client); Ok(take_weak!(self.client).transaction_traces(TransactionId::Hash(transaction_hash.into()))
let traces = client.transaction_traces(TransactionId::Hash(transaction_hash.into())); .map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
Ok(traces)
} }
fn trace(&self, transaction_hash: H256, address: Vec<Index>) -> Result<Option<LocalizedTrace>, Error> { fn trace(&self, transaction_hash: H256, address: Vec<Index>) -> Result<Option<LocalizedTrace>, Error> {
let client = take_weak!(self.client);
let id = TraceId { let id = TraceId {
transaction: TransactionId::Hash(transaction_hash.into()), transaction: TransactionId::Hash(transaction_hash.into()),
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 = trace.map(LocalizedTrace::from);
Ok(trace) Ok(take_weak!(self.client).trace(id)
.map(LocalizedTrace::from))
} }
fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> { fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
let block = block.0; let block = block.0;
let request = CallRequest::into(request); let request = CallRequest::into(request);
let signed = self.sign_call(request)?; let signed = fake_sign::sign_call(&self.client, &self.miner, request)?;
Ok(match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
Ok(e) => Some(TraceResults::from(e)), take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags))
_ => None, .map(TraceResults::from)
}) .map_err(errors::from_call_error)
} }
fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> { fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
let block = block.0; let block = block.0;
UntrustedRlp::new(&raw_transaction.into_vec()).as_val() let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
.map_err(|e| errors::invalid_params("Transaction is not valid RLP", e)) let signed = SignedTransaction::new(tx).map_err(errors::from_transaction_error)?;
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error))
.and_then(|signed| { take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags))
Ok(match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) { .map(TraceResults::from)
Ok(e) => Some(TraceResults::from(e)), .map_err(errors::from_call_error)
_ => None,
})
})
} }
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<Option<TraceResults>, Error> { fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<TraceResults, Error> {
Ok(match take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) { take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags))
Ok(e) => Some(TraceResults::from(e)), .map(TraceResults::from)
_ => None, .map_err(errors::from_call_error)
})
} }
} }

View File

@ -357,7 +357,7 @@ fn rpc_parity_unsigned_transactions_count_when_signer_disabled() {
let io = deps.default_client(); let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_unsignedTransactionsCount", "params":[], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_unsignedTransactionsCount", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#; let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }
@ -393,7 +393,7 @@ fn rpc_parity_signer_port() {
// when // when
let request = r#"{"jsonrpc": "2.0", "method": "parity_signerPort", "params": [], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_signerPort", "params": [], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":18180,"id":1}"#; let response1 = r#"{"jsonrpc":"2.0","result":18180,"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#; let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
// then // then
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned())); assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));
@ -411,7 +411,7 @@ fn rpc_parity_dapps_port() {
// when // when
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsPort", "params": [], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsPort", "params": [], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":18080,"id":1}"#; let response1 = r#"{"jsonrpc":"2.0","result":18080,"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32031,"message":"Dapps Server is disabled. This API is not available.","data":null},"id":1}"#; let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available.","data":null},"id":1}"#;
// then // then
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned())); assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));
@ -429,7 +429,7 @@ fn rpc_parity_dapps_interface() {
// when // when
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsInterface", "params": [], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsInterface", "params": [], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":"127.0.0.1","id":1}"#; let response1 = r#"{"jsonrpc":"2.0","result":"127.0.0.1","id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32031,"message":"Dapps Server is disabled. This API is not available.","data":null},"id":1}"#; let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available.","data":null},"id":1}"#;
// then // then
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned())); assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));

View File

@ -16,17 +16,17 @@
use std::sync::Arc; use std::sync::Arc;
use ethcore::executed::{CallType, Executed}; use ethcore::executed::{CallType, Executed, CallError};
use ethcore::trace::trace::{Action, Res, Call}; use ethcore::trace::trace::{Action, Res, Call};
use ethcore::trace::LocalizedTrace; use ethcore::trace::LocalizedTrace;
use ethcore::client::{TestBlockChainClient}; use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use v1::tests::helpers::{TestMinerService}; use v1::tests::helpers::{TestMinerService};
use v1::{Traces, TracesClient}; use v1::{Traces, TracesClient};
struct Tester { struct Tester {
_client: Arc<TestBlockChainClient>, client: Arc<TestBlockChainClient>,
_miner: Arc<TestMinerService>, _miner: Arc<TestMinerService>,
io: IoHandler, io: IoHandler,
} }
@ -69,7 +69,7 @@ fn io() -> Tester {
io.extend_with(traces.to_delegate()); io.extend_with(traces.to_delegate());
Tester { Tester {
_client: client, client: client,
_miner: miner, _miner: miner,
io: io, io: io,
} }
@ -85,6 +85,17 @@ fn rpc_trace_filter() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_filter_missing_trace() {
let tester = io();
*tester.client.traces.write() = None;
let request = r#"{"jsonrpc":"2.0","method":"trace_filter","params": [{}],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_block() { fn rpc_trace_block() {
let tester = io(); let tester = io();
@ -95,6 +106,17 @@ fn rpc_trace_block() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_block_missing_traces() {
let tester = io();
*tester.client.traces.write() = None;
let request = r#"{"jsonrpc":"2.0","method":"trace_block","params": ["0x10"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_transaction() { fn rpc_trace_transaction() {
let tester = io(); let tester = io();
@ -105,6 +127,17 @@ fn rpc_trace_transaction() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_transaction_missing_trace() {
let tester = io();
*tester.client.traces.write() = None;
let request = r#"{"jsonrpc":"2.0","method":"trace_transaction","params":["0x0000000000000000000000000000000000000000000000000000000000000005"],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_get() { fn rpc_trace_get() {
let tester = io(); let tester = io();
@ -115,6 +148,16 @@ fn rpc_trace_get() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_get_missing_trace() {
let tester = io();
*tester.client.traces.write() = None;
let request = r#"{"jsonrpc":"2.0","method":"trace_get","params":["0x0000000000000000000000000000000000000000000000000000000000000005", ["0","0","0"]],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_call() { fn rpc_trace_call() {
let tester = io(); let tester = io();
@ -125,6 +168,17 @@ fn rpc_trace_call() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_call_state_pruned() {
let tester = io();
*tester.client.execution_result.write() = Some(Err(CallError::StatePruned));
let request = r#"{"jsonrpc":"2.0","method":"trace_call","params":[{}, ["stateDiff", "vmTrace", "trace"]],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"This request is not supported because your node is running with state pruning. Run with --pruning=archive.","data":null},"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_raw_transaction() { fn rpc_trace_raw_transaction() {
let tester = io(); let tester = io();
@ -135,6 +189,17 @@ fn rpc_trace_raw_transaction() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_raw_transaction_state_pruned() {
let tester = io();
*tester.client.execution_result.write() = Some(Err(CallError::StatePruned));
let request = r#"{"jsonrpc":"2.0","method":"trace_rawTransaction","params":["0xf869018609184e72a0008276c094d46e8dd67c5d32be8058bb8eb970870f07244567849184e72a801ba0617f39c1a107b63302449c476d96a6cb17a5842fc98ff0c5bcf4d5c4d8166b95a009fdb6097c6196b9bbafc3a59f02f38d91baeef23d0c60a8e4f23c7714cea3a9", ["stateDiff", "vmTrace", "trace"]],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"This request is not supported because your node is running with state pruning. Run with --pruning=archive.","data":null},"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_trace_replay_transaction() { fn rpc_trace_replay_transaction() {
let tester = io(); let tester = io();
@ -144,3 +209,14 @@ fn rpc_trace_replay_transaction() {
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_trace_replay_transaction_state_pruned() {
let tester = io();
*tester.client.execution_result.write() = Some(Err(CallError::StatePruned));
let request = r#"{"jsonrpc":"2.0","method":"trace_replayTransaction","params":["0x0000000000000000000000000000000000000000000000000000000000000005", ["trace", "stateDiff", "vmTrace"]],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"This request is not supported because your node is running with state pruning. Run with --pruning=archive.","data":null},"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -25,7 +25,7 @@ build_rpc_trait! {
pub trait Traces { pub trait Traces {
/// Returns traces matching given filter. /// Returns traces matching given filter.
#[rpc(name = "trace_filter")] #[rpc(name = "trace_filter")]
fn filter(&self, TraceFilter) -> Result<Vec<LocalizedTrace>, Error>; fn filter(&self, TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error>;
/// Returns transaction trace at given index. /// Returns transaction trace at given index.
#[rpc(name = "trace_get")] #[rpc(name = "trace_get")]
@ -33,22 +33,22 @@ build_rpc_trait! {
/// Returns all traces of given transaction. /// Returns all traces of given transaction.
#[rpc(name = "trace_transaction")] #[rpc(name = "trace_transaction")]
fn transaction_traces(&self, H256) -> Result<Vec<LocalizedTrace>, Error>; fn transaction_traces(&self, H256) -> Result<Option<Vec<LocalizedTrace>>, Error>;
/// Returns all traces produced at given block. /// Returns all traces produced at given block.
#[rpc(name = "trace_block")] #[rpc(name = "trace_block")]
fn block_traces(&self, BlockNumber) -> Result<Vec<LocalizedTrace>, Error>; fn block_traces(&self, BlockNumber) -> Result<Option<Vec<LocalizedTrace>>, Error>;
/// Executes the given call and returns a number of possible traces for it. /// Executes the given call and returns a number of possible traces for it.
#[rpc(name = "trace_call")] #[rpc(name = "trace_call")]
fn call(&self, CallRequest, Vec<String>, Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error>; fn call(&self, CallRequest, Vec<String>, Trailing<BlockNumber>) -> Result<TraceResults, Error>;
/// Executes the given raw transaction and returns a number of possible traces for it. /// Executes the given raw transaction and returns a number of possible traces for it.
#[rpc(name = "trace_rawTransaction")] #[rpc(name = "trace_rawTransaction")]
fn raw_transaction(&self, Bytes, Vec<String>, Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error>; fn raw_transaction(&self, Bytes, Vec<String>, Trailing<BlockNumber>) -> Result<TraceResults, Error>;
/// Executes the transaction with the given hash and returns a number of possible traces for it. /// Executes the transaction with the given hash and returns a number of possible traces for it.
#[rpc(name = "trace_replayTransaction")] #[rpc(name = "trace_replayTransaction")]
fn replay_transaction(&self, H256, Vec<String>) -> Result<Option<TraceResults>, Error>; fn replay_transaction(&self, H256, Vec<String>) -> Result<TraceResults, Error>;
} }
} }