Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Converting traces API to AutoArgs #3844

Merged
merged 2 commits into from
Dec 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub struct TestBlockChainClient {
pub ancient_block: RwLock<Option<(H256, u64)>>,
/// First block info.
pub first_block: RwLock<Option<(H256, u64)>>,
/// Traces to return
pub traces: RwLock<Option<Vec<LocalizedTrace>>>,
}

/// Used for generating test client blocks.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -642,19 +645,19 @@ impl BlockChainClient for TestBlockChainClient {
}

fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
unimplemented!();
self.traces.read().clone()
}

fn trace(&self, _trace: TraceId) -> Option<LocalizedTrace> {
unimplemented!();
self.traces.read().clone().and_then(|vec| vec.into_iter().next())
}

fn transaction_traces(&self, _trace: TransactionId) -> Option<Vec<LocalizedTrace>> {
unimplemented!();
self.traces.read().clone()
}

fn block_traces(&self, _trace: BlockId) -> Option<Vec<LocalizedTrace>> {
unimplemented!();
self.traces.read().clone()
}

fn queue_transactions(&self, transactions: Vec<Bytes>, _peer_id: usize) {
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/types/trace_types/localized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
139 changes: 55 additions & 84 deletions rpc/src/v1/impls/traces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -37,22 +37,6 @@ fn to_call_analytics(flags: Vec<String>) -> 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<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
match params_len(&params) {
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<C, M> where C: BlockChainClient, M: MinerService {
client: Weak<C>,
Expand Down Expand Up @@ -91,90 +75,77 @@ impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService {
}

impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M: MinerService + 'static {
fn filter(&self, params: Params) -> Result<Value, Error> {
fn filter(&self, filter: TraceFilter) -> Result<Vec<LocalizedTrace>, 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<Value, Error> {
fn block_traces(&self, block_number: BlockNumber) -> Result<Vec<LocalizedTrace>, 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<Value, Error> {
fn transaction_traces(&self, transaction_hash: H256) -> Result<Vec<LocalizedTrace>, 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<Value, Error> {
fn trace(&self, transaction_hash: H256, address: Vec<Index>) -> Result<Option<LocalizedTrace>, Error> {
try!(self.active());
from_params::<(H256, Vec<Index>)>(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<Value, Error> {
fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, 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<Value, Error> {
fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, 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<Value, Error> {
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<Option<TraceResults>, 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,
})
}
}
7 changes: 4 additions & 3 deletions rpc/src/v1/tests/mocked/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
145 changes: 145 additions & 0 deletions rpc/src/v1/tests/mocked/traces.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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<TestBlockChainClient>,
_miner: Arc<TestMinerService>,
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()));
}
Loading