From 6e51b23e30029b6df5f4b1c9190fbffb8f2c1efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 14 Dec 2016 20:07:33 +0100 Subject: [PATCH 1/2] Adding traces tests --- ethcore/src/client/test_client.rs | 11 +- ethcore/src/types/trace_types/localized.rs | 2 +- rpc/src/v1/tests/mocked/mod.rs | 7 +- rpc/src/v1/tests/mocked/traces.rs | 145 +++++++++++++++++++++ 4 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 rpc/src/v1/tests/mocked/traces.rs diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 44954f99d..cab703471 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -90,6 +90,8 @@ pub struct TestBlockChainClient { pub ancient_block: RwLock>, /// First block info. pub first_block: RwLock>, + /// Traces to return + pub traces: RwLock>>, } /// Used for generating test client blocks. @@ -151,6 +153,7 @@ impl TestBlockChainClient { latest_block_timestamp: RwLock::new(10_000_000), ancient_block: RwLock::new(None), first_block: RwLock::new(None), + traces: RwLock::new(None), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().clone(); @@ -642,19 +645,19 @@ impl BlockChainClient for TestBlockChainClient { } fn filter_traces(&self, _filter: TraceFilter) -> Option> { - unimplemented!(); + self.traces.read().clone() } fn trace(&self, _trace: TraceId) -> Option { - unimplemented!(); + self.traces.read().clone().and_then(|vec| vec.into_iter().next()) } fn transaction_traces(&self, _trace: TransactionId) -> Option> { - unimplemented!(); + self.traces.read().clone() } fn block_traces(&self, _trace: BlockId) -> Option> { - unimplemented!(); + self.traces.read().clone() } fn queue_transactions(&self, transactions: Vec, _peer_id: usize) { diff --git a/ethcore/src/types/trace_types/localized.rs b/ethcore/src/types/trace_types/localized.rs index 57abea362..f65c47415 100644 --- a/ethcore/src/types/trace_types/localized.rs +++ b/ethcore/src/types/trace_types/localized.rs @@ -21,7 +21,7 @@ use super::trace::{Action, Res}; use header::BlockNumber; /// Localized trace. -#[derive(Debug, PartialEq, Binary)] +#[derive(Debug, PartialEq, Clone, Binary)] pub struct LocalizedTrace { /// Type of action performed by a transaction. pub action: Action, diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index 0ba0fc95c..0dbaa38f6 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -18,13 +18,14 @@ //! method calls properly. mod eth; +mod manage_network; mod net; -mod web3; -mod personal; mod parity; mod parity_accounts; mod parity_set; +mod personal; mod rpc; mod signer; mod signing; -mod manage_network; +mod traces; +mod web3; diff --git a/rpc/src/v1/tests/mocked/traces.rs b/rpc/src/v1/tests/mocked/traces.rs new file mode 100644 index 000000000..f9a9baa00 --- /dev/null +++ b/rpc/src/v1/tests/mocked/traces.rs @@ -0,0 +1,145 @@ +// Copyright 2015, 2016 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 . + +use std::sync::Arc; + +use ethcore::executed::{CallType, Executed}; +use ethcore::trace::trace::{Action, Res, Call}; +use ethcore::trace::LocalizedTrace; +use ethcore::client::{TestBlockChainClient}; + +use jsonrpc_core::{IoHandler, GenericIoHandler}; +use v1::tests::helpers::{TestMinerService}; +use v1::{Traces, TracesClient}; + +struct Tester { + _client: Arc, + _miner: Arc, + io: IoHandler, +} + +fn io() -> Tester { + let client = Arc::new(TestBlockChainClient::new()); + *client.traces.write() = Some(vec![LocalizedTrace { + action: Action::Call(Call { + from: 0xf.into(), + to: 0x10.into(), + value: 0x1.into(), + gas: 0x100.into(), + input: vec![1, 2, 3], + call_type: CallType::Call, + }), + result: Res::None, + subtraces: 0, + trace_address: vec![0], + transaction_number: 0, + transaction_hash: 5.into(), + block_number: 10, + block_hash: 10.into(), + }]); + *client.execution_result.write() = Some(Ok(Executed { + gas: 20_000.into(), + gas_used: 10_000.into(), + refunded: 0.into(), + cumulative_gas_used: 10_000.into(), + logs: vec![], + contracts_created: vec![], + output: vec![1, 2, 3], + trace: vec![], + vm_trace: None, + state_diff: None, + })); + let miner = Arc::new(TestMinerService::default()); + let traces = TracesClient::new(&client, &miner); + let io = IoHandler::new(); + io.add_delegate(traces.to_delegate()); + + Tester { + _client: client, + _miner: miner, + io: io, + } +} + +#[test] +fn rpc_trace_filter() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_filter","params": [{}],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[{"action":{"callType":"call","from":"0x000000000000000000000000000000000000000f","gas":"0x100","input":"0x010203","to":"0x0000000000000000000000000000000000000010","value":"0x1"},"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000a","blockNumber":10,"result":null,"subtraces":0,"traceAddress":[0],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000005","transactionPosition":0,"type":"call"}],"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_block() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_block","params": ["0x10"],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[{"action":{"callType":"call","from":"0x000000000000000000000000000000000000000f","gas":"0x100","input":"0x010203","to":"0x0000000000000000000000000000000000000010","value":"0x1"},"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000a","blockNumber":10,"result":null,"subtraces":0,"traceAddress":[0],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000005","transactionPosition":0,"type":"call"}],"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_transaction() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_transaction","params":["0x0000000000000000000000000000000000000000000000000000000000000005"],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[{"action":{"callType":"call","from":"0x000000000000000000000000000000000000000f","gas":"0x100","input":"0x010203","to":"0x0000000000000000000000000000000000000010","value":"0x1"},"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000a","blockNumber":10,"result":null,"subtraces":0,"traceAddress":[0],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000005","transactionPosition":0,"type":"call"}],"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_get() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_get","params":["0x0000000000000000000000000000000000000000000000000000000000000005", ["0","0","0"]],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"action":{"callType":"call","from":"0x000000000000000000000000000000000000000f","gas":"0x100","input":"0x010203","to":"0x0000000000000000000000000000000000000010","value":"0x1"},"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000a","blockNumber":10,"result":null,"subtraces":0,"traceAddress":[0],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000005","transactionPosition":0,"type":"call"},"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_call() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_call","params":[{}, ["stateDiff", "vmTrace", "trace"]],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"output":"0x010203","stateDiff":null,"trace":[],"vmTrace":null},"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_raw_transaction() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_rawTransaction","params":["0xf869018609184e72a0008276c094d46e8dd67c5d32be8058bb8eb970870f07244567849184e72a801ba0617f39c1a107b63302449c476d96a6cb17a5842fc98ff0c5bcf4d5c4d8166b95a009fdb6097c6196b9bbafc3a59f02f38d91baeef23d0c60a8e4f23c7714cea3a9", ["stateDiff", "vmTrace", "trace"]],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"output":"0x010203","stateDiff":null,"trace":[],"vmTrace":null},"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_trace_replay_transaction() { + let tester = io(); + + let request = r#"{"jsonrpc":"2.0","method":"trace_replayTransaction","params":["0x0000000000000000000000000000000000000000000000000000000000000005", ["trace", "stateDiff", "vmTrace"]],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"output":"0x010203","stateDiff":null,"trace":[],"vmTrace":null},"id":1}"#; + + assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); +} From d2b9bc5bd8fca75bfcdbad8640ddd47e654b291c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 14 Dec 2016 20:09:14 +0100 Subject: [PATCH 2/2] Traces to AutoArgs --- rpc/src/v1/impls/traces.rs | 139 ++++++++++++++---------------------- rpc/src/v1/traits/traces.rs | 58 +++++++-------- 2 files changed, 82 insertions(+), 115 deletions(-) diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 6b37e40cc..5f42c0cf3 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -17,14 +17,14 @@ //! Traces api implementation. use std::sync::{Weak, Arc}; -use jsonrpc_core::*; -use serde; use rlp::{UntrustedRlp, View}; use ethcore::client::{BlockChainClient, CallAnalytics, TransactionId, TraceId}; use ethcore::miner::MinerService; use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; +use jsonrpc_core::Error; +use jsonrpc_macros::Trailing; use v1::traits::Traces; use v1::helpers::{errors, CallRequest as CRequest}; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256}; @@ -37,22 +37,6 @@ fn to_call_analytics(flags: Vec) -> CallAnalytics { } } -/// Returns number of different parameters in given `Params` object. -fn params_len(params: &Params) -> usize { - match params { - &Params::Array(ref vec) => vec.len(), - _ => 0, - } -} - -/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`. -fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize { - match params_len(¶ms) { - 2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)), - _ => from_params::<(F1, F2, BlockNumber)>(params) - } -} - /// Traces api implementation. pub struct TracesClient where C: BlockChainClient, M: MinerService { client: Weak, @@ -91,90 +75,77 @@ impl TracesClient where C: BlockChainClient, M: MinerService { } impl Traces for TracesClient where C: BlockChainClient + 'static, M: MinerService + 'static { - fn filter(&self, params: Params) -> Result { + fn filter(&self, filter: TraceFilter) -> Result, Error> { try!(self.active()); - from_params::<(TraceFilter,)>(params) - .and_then(|(filter, )| { - 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(to_value(&traces)) - }) + + 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) } - fn block_traces(&self, params: Params) -> Result { + fn block_traces(&self, block_number: BlockNumber) -> Result, Error> { try!(self.active()); - from_params::<(BlockNumber,)>(params) - .and_then(|(block_number,)| { - 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(to_value(&traces)) - }) + 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 transaction_traces(&self, params: Params) -> Result { + fn transaction_traces(&self, transaction_hash: H256) -> Result, Error> { try!(self.active()); - from_params::<(H256,)>(params) - .and_then(|(transaction_hash,)| { - 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(to_value(&traces)) - }) + + 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 trace(&self, params: Params) -> Result { + fn trace(&self, transaction_hash: H256, address: Vec) -> Result, Error> { try!(self.active()); - from_params::<(H256, Vec)>(params) - .and_then(|(transaction_hash, address)| { - 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(to_value(&trace)) - }) + 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) } - fn call(&self, params: Params) -> Result { + fn call(&self, request: CallRequest, flags: Vec, block: Trailing) -> Result, Error> { try!(self.active()); - from_params_default_third(params) - .and_then(|(request, flags, block)| { - let request = CallRequest::into(request); - let signed = try!(self.sign_call(request)); - match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) { - Ok(e) => Ok(to_value(&TraceResults::from(e))), - _ => Ok(Value::Null), - } - }) + let block = block.0; + + let request = CallRequest::into(request); + let signed = try!(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, + }) } - fn raw_transaction(&self, params: Params) -> Result { + fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec, block: Trailing) -> Result, Error> { try!(self.active()); - from_params_default_third(params) - .and_then(|(raw_transaction, flags, block)| { - let raw_transaction = Bytes::to_vec(raw_transaction); - match UntrustedRlp::new(&raw_transaction).as_val() { - Ok(signed) => match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) { - Ok(e) => Ok(to_value(&TraceResults::from(e))), - _ => Ok(Value::Null), - }, - Err(e) => Err(errors::invalid_params("Transaction is not valid RLP", e)), - } - }) + let block = block.0; + + let raw_transaction = Bytes::to_vec(raw_transaction); + match UntrustedRlp::new(&raw_transaction).as_val() { + Ok(signed) => Ok(match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) { + Ok(e) => Some(TraceResults::from(e)), + _ => None, + }), + Err(e) => Err(errors::invalid_params("Transaction is not valid RLP", e)), + } } - fn replay_transaction(&self, params: Params) -> Result { + fn replay_transaction(&self, transaction_hash: H256, flags: Vec) -> Result, Error> { try!(self.active()); - from_params::<(H256, _)>(params) - .and_then(|(transaction_hash, flags)| { - match take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) { - Ok(e) => Ok(to_value(&TraceResults::from(e))), - _ => Ok(Value::Null), - } - }) + + Ok(match take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) { + Ok(e) => Some(TraceResults::from(e)), + _ => None, + }) } } diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index 36561216f..1d5fef5ec 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -16,43 +16,39 @@ //! Traces specific rpc interface. -use std::sync::Arc; -use jsonrpc_core::{Params, Value, Error, IoDelegate}; +use jsonrpc_core::Error; +use jsonrpc_macros::Trailing; +use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256}; -/// Traces specific rpc interface. -pub trait Traces: Sized + Send + Sync + 'static { - /// Returns traces matching given filter. - fn filter(&self, _: Params) -> Result; +build_rpc_trait! { + /// Traces specific rpc interface. + pub trait Traces { + /// Returns traces matching given filter. + #[rpc(name = "trace_filter")] + fn filter(&self, TraceFilter) -> Result, Error>; - /// Returns transaction trace at given index. - fn trace(&self, _: Params) -> Result; + /// Returns transaction trace at given index. + #[rpc(name = "trace_get")] + fn trace(&self, H256, Vec) -> Result, Error>; - /// Returns all traces of given transaction. - fn transaction_traces(&self, _: Params) -> Result; + /// Returns all traces of given transaction. + #[rpc(name = "trace_transaction")] + fn transaction_traces(&self, H256) -> Result, Error>; - /// Returns all traces produced at given block. - fn block_traces(&self, _: Params) -> Result; + /// Returns all traces produced at given block. + #[rpc(name = "trace_block")] + fn block_traces(&self, BlockNumber) -> Result, Error>; - /// Executes the given call and returns a number of possible traces for it. - fn call(&self, _: Params) -> Result; + /// Executes the given call and returns a number of possible traces for it. + #[rpc(name = "trace_call")] + fn call(&self, CallRequest, Vec, Trailing) -> Result, Error>; - /// Executes the given raw transaction and returns a number of possible traces for it. - fn raw_transaction(&self, _: Params) -> Result; + /// Executes the given raw transaction and returns a number of possible traces for it. + #[rpc(name = "trace_rawTransaction")] + fn raw_transaction(&self, Bytes, Vec, Trailing) -> Result, Error>; - /// Executes the transaction with the given hash and returns a number of possible traces for it. - fn replay_transaction(&self, _: Params) -> Result; - - /// Should be used to convert object to io delegate. - fn to_delegate(self) -> IoDelegate { - let mut delegate = IoDelegate::new(Arc::new(self)); - delegate.add_method("trace_filter", Traces::filter); - delegate.add_method("trace_get", Traces::trace); - delegate.add_method("trace_transaction", Traces::transaction_traces); - delegate.add_method("trace_block", Traces::block_traces); - delegate.add_method("trace_call", Traces::call); - delegate.add_method("trace_rawTransaction", Traces::raw_transaction); - delegate.add_method("trace_replayTransaction", Traces::replay_transaction); - - delegate + /// 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) -> Result, Error>; } }