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
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use trace::Error as TraceError;
use util::UtilError;
use std::fmt::{Display, Formatter, Error as FmtError};
@ -23,8 +22,6 @@ use util::trie::TrieError;
/// Client configuration errors.
#[derive(Debug)]
pub enum Error {
/// TraceDB configuration error.
Trace(TraceError),
/// TrieDB-related error.
Trie(TrieError),
/// Database error
@ -33,12 +30,6 @@ pub enum Error {
Util(UtilError),
}
impl From<TraceError> for Error {
fn from(err: TraceError) -> Self {
Error::Trace(err)
}
}
impl From<TrieError> for Error {
fn from(err: TrieError) -> Self {
Error::Trie(err)
@ -60,7 +51,6 @@ impl<E> From<Box<E>> for Error where Error: From<E> {
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Error::Trace(ref err) => write!(f, "{}", err),
Error::Trie(ref err) => write!(f, "{}", err),
Error::Util(ref err) => write!(f, "{}", err),
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 config;
mod db;
mod error;
mod executive_tracer;
mod import;
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 self::config::Config;
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::flat::{FlatTrace, FlatTransactionTraces, FlatBlockTraces};
pub use self::noop_tracer::{NoopTracer, NoopVMTracer};

View File

@ -32,7 +32,6 @@ mod codes {
pub const NO_WORK: i64 = -32001;
pub const NO_AUTHOR: i64 = -32002;
pub const NO_NEW_WORK: i64 = -32003;
pub const NOT_ENOUGH_DATA: i64 = -32006;
pub const UNKNOWN_ERROR: i64 = -32009;
pub const TRANSACTION_ERROR: i64 = -32010;
pub const EXECUTION_ERROR: i64 = -32015;
@ -41,9 +40,6 @@ mod codes {
pub const ACCOUNT_LOCKED: i64 = -32020;
pub const PASSWORD_INVALID: i64 = -32021;
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_LIMIT: i64 = -32041;
pub const REQUEST_NOT_FOUND: i64 = -32042;
@ -174,9 +170,9 @@ pub fn no_author() -> Error {
pub fn not_enough_data() -> 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(),
data: None
data: None,
}
}
@ -190,25 +186,25 @@ pub fn token(e: String) -> Error {
pub fn signer_disabled() -> 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(),
data: None
data: None,
}
}
pub fn dapps_disabled() -> 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(),
data: None
data: None,
}
}
pub fn network_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::NETWORK_DISABLED),
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
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 {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
code: ErrorCode::InvalidParams,
message: "Unknown block number".into(),
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 dispatch;
pub mod fake_sign;
pub mod informant;
mod network_settings;

View File

@ -23,7 +23,7 @@ use std::sync::{Arc, Weak};
use futures::{self, future, BoxFuture, Future};
use rlp::{self, UntrustedRlp, View};
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::Mutex;
@ -36,14 +36,14 @@ use ethcore::filter::Filter as EthcoreFilter;
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
use ethcore::log_entry::LogEntry;
use ethcore::miner::{MinerService, ExternalMinerService};
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
use ethcore::transaction::SignedTransaction;
use ethcore::snapshot::SnapshotService;
use ethsync::{SyncProvider};
use jsonrpc_core::Error;
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::block_import::is_major_importing;
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))
}
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> {
let store = take_weak!(self.accounts);
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> {
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,
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> {
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,
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;
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))
}
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))
}
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))
}
@ -43,15 +43,15 @@ impl Traces for TracesClient {
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))
}
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))
}
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))
}
}

View File

@ -19,14 +19,14 @@
use std::sync::{Weak, Arc};
use rlp::{UntrustedRlp, View};
use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId};
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId};
use ethcore::miner::MinerService;
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
use ethcore::transaction::SignedTransaction;
use jsonrpc_core::Error;
use jsonrpc_macros::Trailing;
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};
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
@ -38,12 +38,12 @@ fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
}
/// Traces api implementation.
pub struct TracesClient<C, M> where C: BlockChainClient, M: MinerService {
pub struct TracesClient<C, M> {
client: Weak<C>,
miner: Weak<M>,
}
impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService {
impl<C, M> TracesClient<C, M> {
/// Creates new Traces client.
pub fn new(client: &Arc<C>, miner: &Arc<M>) -> Self {
TracesClient {
@ -51,86 +51,59 @@ impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService {
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 {
fn filter(&self, filter: TraceFilter) -> Result<Vec<LocalizedTrace>, Error> {
let client = take_weak!(self.client);
let traces = client.filter_traces(filter.into());
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
Ok(traces)
impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'static, M: MinerService + 'static {
fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> {
Ok(take_weak!(self.client).filter_traces(filter.into())
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
}
fn block_traces(&self, block_number: BlockNumber) -> Result<Vec<LocalizedTrace>, Error> {
let client = take_weak!(self.client);
let traces = client.block_traces(block_number.into());
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<Option<Vec<LocalizedTrace>>, Error> {
Ok(take_weak!(self.client).block_traces(block_number.into())
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
}
fn transaction_traces(&self, transaction_hash: H256) -> Result<Vec<LocalizedTrace>, Error> {
let client = take_weak!(self.client);
let traces = client.transaction_traces(TransactionId::Hash(transaction_hash.into()));
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<Option<Vec<LocalizedTrace>>, Error> {
Ok(take_weak!(self.client).transaction_traces(TransactionId::Hash(transaction_hash.into()))
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
}
fn trace(&self, transaction_hash: H256, address: Vec<Index>) -> Result<Option<LocalizedTrace>, Error> {
let client = take_weak!(self.client);
let id = TraceId {
transaction: TransactionId::Hash(transaction_hash.into()),
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 request = CallRequest::into(request);
let signed = self.sign_call(request)?;
Ok(match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
Ok(e) => Some(TraceResults::from(e)),
_ => None,
})
let signed = fake_sign::sign_call(&self.client, &self.miner, request)?;
take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags))
.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;
UntrustedRlp::new(&raw_transaction.into_vec()).as_val()
.map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error))
.and_then(|signed| {
Ok(match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
Ok(e) => Some(TraceResults::from(e)),
_ => None,
})
})
let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
let signed = SignedTransaction::new(tx).map_err(errors::from_transaction_error)?;
take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags))
.map(TraceResults::from)
.map_err(errors::from_call_error)
}
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<Option<TraceResults>, Error> {
Ok(match take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) {
Ok(e) => Some(TraceResults::from(e)),
_ => None,
})
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<TraceResults, Error> {
take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags))
.map(TraceResults::from)
.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 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()));
}
@ -393,7 +393,7 @@ fn rpc_parity_signer_port() {
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_signerPort", "params": [], "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
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));
@ -411,7 +411,7 @@ fn rpc_parity_dapps_port() {
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsPort", "params": [], "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
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));
@ -429,7 +429,7 @@ fn rpc_parity_dapps_interface() {
// when
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 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
assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned()));

View File

@ -16,17 +16,17 @@
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::LocalizedTrace;
use ethcore::client::{TestBlockChainClient};
use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler;
use v1::tests::helpers::{TestMinerService};
use v1::{Traces, TracesClient};
struct Tester {
_client: Arc<TestBlockChainClient>,
client: Arc<TestBlockChainClient>,
_miner: Arc<TestMinerService>,
io: IoHandler,
}
@ -69,7 +69,7 @@ fn io() -> Tester {
io.extend_with(traces.to_delegate());
Tester {
_client: client,
client: client,
_miner: miner,
io: io,
}
@ -85,6 +85,17 @@ fn rpc_trace_filter() {
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]
fn rpc_trace_block() {
let tester = io();
@ -95,6 +106,17 @@ fn rpc_trace_block() {
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]
fn rpc_trace_transaction() {
let tester = io();
@ -105,6 +127,17 @@ fn rpc_trace_transaction() {
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]
fn rpc_trace_get() {
let tester = io();
@ -115,6 +148,16 @@ fn rpc_trace_get() {
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]
fn rpc_trace_call() {
let tester = io();
@ -125,6 +168,17 @@ fn rpc_trace_call() {
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]
fn rpc_trace_raw_transaction() {
let tester = io();
@ -135,6 +189,17 @@ fn rpc_trace_raw_transaction() {
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]
fn rpc_trace_replay_transaction() {
let tester = io();
@ -144,3 +209,14 @@ fn rpc_trace_replay_transaction() {
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 {
/// Returns traces matching given 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.
#[rpc(name = "trace_get")]
@ -33,22 +33,22 @@ build_rpc_trait! {
/// Returns all traces of given 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.
#[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.
#[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.
#[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.
#[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>;
}
}