Tracedb interface && cli (#997)
* traces cli and jsonrpc api * missing if in docs * adding traces to modules
This commit is contained in:
parent
e22e4b9b8b
commit
7c2adc4137
@ -37,12 +37,14 @@ use filter::Filter;
|
||||
use log_entry::LocalizedLogEntry;
|
||||
use block_queue::{BlockQueue, BlockQueueInfo};
|
||||
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||
use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient};
|
||||
use client::{BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, TraceFilter};
|
||||
use env_info::EnvInfo;
|
||||
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||
use receipt::LocalizedReceipt;
|
||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||
use trace::{TraceDB, Database as TraceDatabase};
|
||||
use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase, Filter as
|
||||
TracedbFilter};
|
||||
use trace;
|
||||
|
||||
/// General block status
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
@ -309,6 +311,8 @@ impl<V> Client<V> where V: Verifier {
|
||||
// Commit results
|
||||
let closed_block = closed_block.unwrap();
|
||||
let receipts = closed_block.block().receipts().clone();
|
||||
let traces = From::from(closed_block.block().traces().clone().unwrap_or_else(Vec::new));
|
||||
|
||||
closed_block.drain()
|
||||
.commit(header.number(), &header.hash(), ancient)
|
||||
.expect("State DB commit failed.");
|
||||
@ -316,6 +320,14 @@ impl<V> Client<V> where V: Verifier {
|
||||
// And update the chain after commit to prevent race conditions
|
||||
// (when something is in chain but you are not able to fetch details)
|
||||
let route = self.chain.insert_block(&block.bytes, receipts);
|
||||
self.tracedb.import(TraceImportRequest {
|
||||
traces: traces,
|
||||
block_hash: header.hash(),
|
||||
block_number: header.number(),
|
||||
enacted: route.enacted.clone(),
|
||||
retracted: route.retracted.len()
|
||||
});
|
||||
|
||||
import_results.push(route);
|
||||
|
||||
self.report.write().unwrap().accrue_block(&block);
|
||||
@ -707,6 +719,46 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
|
||||
let start = self.block_number(filter.range.start);
|
||||
let end = self.block_number(filter.range.end);
|
||||
|
||||
if start.is_some() && end.is_some() {
|
||||
let filter = trace::Filter {
|
||||
range: start.unwrap() as usize..end.unwrap() as usize,
|
||||
from_address: From::from(filter.from_address),
|
||||
to_address: From::from(filter.to_address),
|
||||
};
|
||||
|
||||
let traces = self.tracedb.filter(&filter);
|
||||
Some(traces)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn trace(&self, trace: TraceId) -> Option<LocalizedTrace> {
|
||||
let trace_address = trace.address;
|
||||
self.transaction_address(trace.transaction)
|
||||
.and_then(|tx_address| {
|
||||
self.block_number(BlockId::Hash(tx_address.block_hash))
|
||||
.and_then(|number| self.tracedb.trace(number, tx_address.index, trace_address))
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_traces(&self, transaction: TransactionId) -> Option<Vec<LocalizedTrace>> {
|
||||
self.transaction_address(transaction)
|
||||
.and_then(|tx_address| {
|
||||
self.block_number(BlockId::Hash(tx_address.block_hash))
|
||||
.and_then(|number| self.tracedb.transaction_traces(number, tx_address.index))
|
||||
})
|
||||
}
|
||||
|
||||
fn block_traces(&self, block: BlockId) -> Option<Vec<LocalizedTrace>> {
|
||||
self.block_number(block)
|
||||
.and_then(|number| self.tracedb.block_traces(number))
|
||||
}
|
||||
|
||||
fn last_hashes(&self) -> LastHashes {
|
||||
self.build_last_hashes(self.chain.best_block_hash())
|
||||
}
|
||||
|
@ -44,6 +44,14 @@ pub enum TransactionId {
|
||||
Location(BlockId, usize)
|
||||
}
|
||||
|
||||
/// Uniquely identifies Trace.
|
||||
pub struct TraceId {
|
||||
/// Transaction
|
||||
pub transaction: TransactionId,
|
||||
/// Trace address within transaction.
|
||||
pub address: Vec<usize>,
|
||||
}
|
||||
|
||||
/// Uniquely identifies Uncle.
|
||||
pub struct UncleId (
|
||||
/// Block id.
|
||||
|
@ -23,9 +23,10 @@ mod test_client;
|
||||
mod trace;
|
||||
|
||||
pub use self::client::*;
|
||||
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig};
|
||||
pub use self::ids::{BlockId, TransactionId, UncleId};
|
||||
pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch};
|
||||
pub use self::ids::{BlockId, TransactionId, UncleId, TraceId};
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
pub use self::trace::Filter as TraceFilter;
|
||||
pub use executive::{Executed, Executive, TransactOptions};
|
||||
pub use env_info::{LastHashes, EnvInfo};
|
||||
|
||||
@ -43,6 +44,7 @@ use filter::Filter;
|
||||
use error::{ImportResult, Error};
|
||||
use receipt::LocalizedReceipt;
|
||||
use engine::{Engine};
|
||||
use trace::LocalizedTrace;
|
||||
|
||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||
pub trait BlockChainClient : Sync + Send {
|
||||
@ -135,6 +137,18 @@ pub trait BlockChainClient : Sync + Send {
|
||||
/// Executes a function providing it with a reference to an engine.
|
||||
fn engine(&self) -> &Engine;
|
||||
|
||||
/// Returns traces matching given filter.
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>;
|
||||
|
||||
/// Returns trace with given id.
|
||||
fn trace(&self, trace: TraceId) -> Option<LocalizedTrace>;
|
||||
|
||||
/// Returns traces created by transaction.
|
||||
fn transaction_traces(&self, trace: TransactionId) -> Option<Vec<LocalizedTrace>>;
|
||||
|
||||
/// Returns traces created by transaction from block.
|
||||
fn block_traces(&self, trace: BlockId) -> Option<Vec<LocalizedTrace>>;
|
||||
|
||||
/// Get last hashes starting from best block.
|
||||
fn last_hashes(&self) -> LastHashes;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
|
||||
use util::*;
|
||||
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
|
||||
use blockchain::TreeRoute;
|
||||
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, LastHashes};
|
||||
use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes};
|
||||
use header::{Header as BlockHeader, BlockNumber};
|
||||
use filter::Filter;
|
||||
use log_entry::LocalizedLogEntry;
|
||||
@ -33,6 +33,7 @@ use block::{SealedBlock, ClosedBlock, LockedBlock};
|
||||
use executive::Executed;
|
||||
use error::Error;
|
||||
use engine::Engine;
|
||||
use trace::LocalizedTrace;
|
||||
|
||||
/// Test client.
|
||||
pub struct TestBlockChainClient {
|
||||
@ -432,4 +433,20 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
fn engine(&self) -> &Engine {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn trace(&self, _trace: TraceId) -> Option<LocalizedTrace> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn transaction_traces(&self, _trace: TransactionId) -> Option<Vec<LocalizedTrace>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn block_traces(&self, _trace: BlockId) -> Option<Vec<LocalizedTrace>> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ API and Console Options:
|
||||
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
|
||||
interface. APIS is a comma-delimited list of API
|
||||
name. Possible name are web3, eth and net.
|
||||
[default: web3,eth,net,personal,ethcore].
|
||||
[default: web3,eth,net,personal,ethcore,traces].
|
||||
-w --webapp Enable the web applications server (e.g.
|
||||
status page).
|
||||
--webapp-port PORT Specify the port portion of the WebApps server
|
||||
@ -103,6 +103,11 @@ Sealing/Mining Options:
|
||||
be included in next block) [default: 1024].
|
||||
|
||||
Footprint Options:
|
||||
--tracing BOOL Indicates if full transaction tracing should be
|
||||
enabled. Works only if client had been fully synced with
|
||||
tracing enabled. BOOL may be one of auto, on, off.
|
||||
auto uses last used value of this option (off if it does
|
||||
not exist) [default: auto].
|
||||
--pruning METHOD Configure pruning of the state/storage trie. METHOD
|
||||
may be one of auto, archive, basic, fast, light:
|
||||
archive - keep all state trie data. No pruning.
|
||||
@ -164,6 +169,7 @@ pub struct Args {
|
||||
pub flag_bootnodes: Option<String>,
|
||||
pub flag_network_id: Option<String>,
|
||||
pub flag_pruning: String,
|
||||
pub flag_tracing: String,
|
||||
pub flag_port: u16,
|
||||
pub flag_peers: usize,
|
||||
pub flag_no_discovery: bool,
|
||||
|
@ -26,7 +26,7 @@ use die::*;
|
||||
use util::*;
|
||||
use util::keys::store::AccountService;
|
||||
use util::network_settings::NetworkSettings;
|
||||
use ethcore::client::{append_path, get_db_path, ClientConfig};
|
||||
use ethcore::client::{append_path, get_db_path, ClientConfig, Switch};
|
||||
use ethcore::ethereum;
|
||||
use ethcore::spec::Spec;
|
||||
use ethsync::SyncConfig;
|
||||
@ -207,6 +207,12 @@ impl Configuration {
|
||||
client_config.blockchain.max_cache_size = self.args.flag_cache_max_size;
|
||||
}
|
||||
}
|
||||
client_config.tracing.enabled = match self.args.flag_tracing.as_str() {
|
||||
"auto" => Switch::Auto,
|
||||
"on" => Switch::On,
|
||||
"off" => Switch::Off,
|
||||
_ => { die!("Invalid tracing method given!") }
|
||||
};
|
||||
client_config.pruning = match self.args.flag_pruning.as_str() {
|
||||
"archive" => journaldb::Algorithm::Archive,
|
||||
"light" => journaldb::Algorithm::EarlyMerge,
|
||||
|
@ -99,7 +99,7 @@ pub fn setup_rpc_server(
|
||||
server.add_delegate(Web3Client::new().to_delegate());
|
||||
},
|
||||
"net" => {
|
||||
modules.insert("web3".to_owned(), "1.0".to_owned());
|
||||
modules.insert("net".to_owned(), "1.0".to_owned());
|
||||
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
|
||||
},
|
||||
"eth" => {
|
||||
@ -115,6 +115,10 @@ pub fn setup_rpc_server(
|
||||
// not adding to modules, since `ethcore` is not supported in geth
|
||||
server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
|
||||
},
|
||||
"traces" => {
|
||||
modules.insert("traces".to_owned(), "1.0".to_owned());
|
||||
server.add_delegate(TracesClient::new(&deps.client).to_delegate())
|
||||
},
|
||||
_ => {
|
||||
die!("{}: Invalid API name to be enabled.", api);
|
||||
},
|
||||
|
@ -30,6 +30,7 @@ mod eth;
|
||||
mod net;
|
||||
mod personal;
|
||||
mod ethcore;
|
||||
mod traces;
|
||||
mod rpc;
|
||||
|
||||
pub use self::web3::Web3Client;
|
||||
@ -37,5 +38,6 @@ pub use self::eth::{EthClient, EthFilterClient};
|
||||
pub use self::net::NetClient;
|
||||
pub use self::personal::PersonalClient;
|
||||
pub use self::ethcore::EthcoreClient;
|
||||
pub use self::traces::TracesClient;
|
||||
pub use self::rpc::RpcClient;
|
||||
|
||||
|
84
rpc/src/v1/impls/traces.rs
Normal file
84
rpc/src/v1/impls/traces.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Traces api implementation.
|
||||
|
||||
use std::sync::{Weak, Arc};
|
||||
use jsonrpc_core::*;
|
||||
use util::H256;
|
||||
use ethcore::client::{BlockChainClient, TransactionId, TraceId};
|
||||
use v1::traits::Traces;
|
||||
use v1::types::{TraceFilter, Trace, BlockNumber, Index};
|
||||
|
||||
/// Traces api implementation.
|
||||
pub struct TracesClient<C> where C: BlockChainClient {
|
||||
client: Weak<C>,
|
||||
}
|
||||
|
||||
impl<C> TracesClient<C> where C: BlockChainClient {
|
||||
/// Creates new Traces client.
|
||||
pub fn new(client: &Arc<C>) -> Self {
|
||||
TracesClient {
|
||||
client: Arc::downgrade(client),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Traces for TracesClient<C> where C: BlockChainClient + 'static {
|
||||
fn filter(&self, params: Params) -> Result<Value, Error> {
|
||||
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(Trace::from).collect());
|
||||
to_value(&traces)
|
||||
})
|
||||
}
|
||||
|
||||
fn block_traces(&self, params: Params) -> Result<Value, Error> {
|
||||
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(Trace::from).collect());
|
||||
to_value(&traces)
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_traces(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params::<(H256,)>(params)
|
||||
.and_then(|(transaction_hash,)| {
|
||||
let client = take_weak!(self.client);
|
||||
let traces = client.transaction_traces(TransactionId::Hash(transaction_hash));
|
||||
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(Trace::from).collect());
|
||||
to_value(&traces)
|
||||
})
|
||||
}
|
||||
|
||||
fn trace(&self, params: Params) -> Result<Value, Error> {
|
||||
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),
|
||||
address: address.into_iter().map(|i| i.value()).collect()
|
||||
};
|
||||
let trace = client.trace(id);
|
||||
let trace = trace.map(Trace::from);
|
||||
to_value(&trace)
|
||||
})
|
||||
}
|
||||
}
|
@ -25,5 +25,5 @@ mod helpers;
|
||||
|
||||
pub mod tests;
|
||||
|
||||
pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Rpc};
|
||||
pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc};
|
||||
pub use self::impls::*;
|
||||
|
@ -25,6 +25,7 @@ pub mod eth;
|
||||
pub mod net;
|
||||
pub mod personal;
|
||||
pub mod ethcore;
|
||||
pub mod traces;
|
||||
pub mod rpc;
|
||||
|
||||
pub use self::web3::Web3;
|
||||
@ -32,4 +33,5 @@ pub use self::eth::{Eth, EthFilter};
|
||||
pub use self::net::Net;
|
||||
pub use self::personal::Personal;
|
||||
pub use self::ethcore::Ethcore;
|
||||
pub use self::traces::Traces;
|
||||
pub use self::rpc::Rpc;
|
||||
|
44
rpc/src/v1/traits/traces.rs
Normal file
44
rpc/src/v1/traits/traces.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Traces specific rpc interface.
|
||||
use std::sync::Arc;
|
||||
use jsonrpc_core::*;
|
||||
|
||||
/// Traces specific rpc interface.
|
||||
pub trait Traces: Sized + Send + Sync + 'static {
|
||||
/// Returns traces matching given filter.
|
||||
fn filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||
|
||||
/// Returns transaction trace at given index.
|
||||
fn trace(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||
|
||||
/// Returns all traces of given transaction.
|
||||
fn transaction_traces(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||
|
||||
/// Returns all traces produced at given block.
|
||||
fn block_traces(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||
|
||||
/// Should be used to convert object to io delegate.
|
||||
fn to_delegate(self) -> IoDelegate<Self> {
|
||||
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
|
||||
}
|
||||
}
|
@ -26,6 +26,8 @@ mod transaction;
|
||||
mod transaction_request;
|
||||
mod call_request;
|
||||
mod receipt;
|
||||
mod trace;
|
||||
mod trace_filter;
|
||||
|
||||
pub use self::block::{Block, BlockTransactions};
|
||||
pub use self::block_number::BlockNumber;
|
||||
@ -39,4 +41,5 @@ pub use self::transaction::Transaction;
|
||||
pub use self::transaction_request::TransactionRequest;
|
||||
pub use self::call_request::CallRequest;
|
||||
pub use self::receipt::Receipt;
|
||||
|
||||
pub use self::trace::Trace;
|
||||
pub use self::trace_filter::TraceFilter;
|
||||
|
238
rpc/src/v1/types/trace.rs
Normal file
238
rpc/src/v1/types/trace.rs
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use util::{Address, U256, H256};
|
||||
use ethcore::trace::trace;
|
||||
use ethcore::trace::LocalizedTrace;
|
||||
use v1::types::Bytes;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Create {
|
||||
from: Address,
|
||||
value: U256,
|
||||
gas: U256,
|
||||
init: Bytes,
|
||||
}
|
||||
|
||||
impl From<trace::Create> for Create {
|
||||
fn from(c: trace::Create) -> Self {
|
||||
Create {
|
||||
from: c.from,
|
||||
value: c.value,
|
||||
gas: c.gas,
|
||||
init: Bytes::new(c.init),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Call {
|
||||
from: Address,
|
||||
to: Address,
|
||||
value: U256,
|
||||
gas: U256,
|
||||
input: Bytes,
|
||||
}
|
||||
|
||||
impl From<trace::Call> for Call {
|
||||
fn from(c: trace::Call) -> Self {
|
||||
Call {
|
||||
from: c.from,
|
||||
to: c.to,
|
||||
value: c.value,
|
||||
gas: c.gas,
|
||||
input: Bytes::new(c.input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum Action {
|
||||
#[serde(rename="call")]
|
||||
Call(Call),
|
||||
#[serde(rename="create")]
|
||||
Create(Create),
|
||||
}
|
||||
|
||||
impl From<trace::Action> for Action {
|
||||
fn from(c: trace::Action) -> Self {
|
||||
match c {
|
||||
trace::Action::Call(call) => Action::Call(Call::from(call)),
|
||||
trace::Action::Create(create) => Action::Create(Create::from(create)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CallResult {
|
||||
#[serde(rename="gasUsed")]
|
||||
gas_used: U256,
|
||||
output: Bytes,
|
||||
}
|
||||
|
||||
impl From<trace::CallResult> for CallResult {
|
||||
fn from(c: trace::CallResult) -> Self {
|
||||
CallResult {
|
||||
gas_used: c.gas_used,
|
||||
output: Bytes::new(c.output),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CreateResult {
|
||||
#[serde(rename="gasUsed")]
|
||||
gas_used: U256,
|
||||
code: Bytes,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl From<trace::CreateResult> for CreateResult {
|
||||
fn from(c: trace::CreateResult) -> Self {
|
||||
CreateResult {
|
||||
gas_used: c.gas_used,
|
||||
code: Bytes::new(c.code),
|
||||
address: c.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum Res {
|
||||
#[serde(rename="call")]
|
||||
Call(CallResult),
|
||||
#[serde(rename="create")]
|
||||
Create(CreateResult),
|
||||
#[serde(rename="failedCall")]
|
||||
FailedCall,
|
||||
#[serde(rename="failedCreate")]
|
||||
FailedCreate,
|
||||
}
|
||||
|
||||
impl From<trace::Res> for Res {
|
||||
fn from(t: trace::Res) -> Self {
|
||||
match t {
|
||||
trace::Res::Call(call) => Res::Call(CallResult::from(call)),
|
||||
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
||||
trace::Res::FailedCall => Res::FailedCall,
|
||||
trace::Res::FailedCreate => Res::FailedCreate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Trace {
|
||||
action: Action,
|
||||
result: Res,
|
||||
#[serde(rename="traceAddress")]
|
||||
trace_address: Vec<U256>,
|
||||
subtraces: U256,
|
||||
#[serde(rename="transactionPosition")]
|
||||
transaction_position: U256,
|
||||
#[serde(rename="transactionHash")]
|
||||
transaction_hash: H256,
|
||||
#[serde(rename="blockNumber")]
|
||||
block_number: U256,
|
||||
#[serde(rename="blockHash")]
|
||||
block_hash: H256,
|
||||
}
|
||||
|
||||
impl From<LocalizedTrace> for Trace {
|
||||
fn from(t: LocalizedTrace) -> Self {
|
||||
Trace {
|
||||
action: From::from(t.action),
|
||||
result: From::from(t.result),
|
||||
trace_address: t.trace_address.into_iter().map(From::from).collect(),
|
||||
subtraces: From::from(t.subtraces),
|
||||
transaction_position: From::from(t.transaction_number),
|
||||
transaction_hash: t.transaction_hash,
|
||||
block_number: From::from(t.block_number),
|
||||
block_hash: t.block_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use util::{U256, H256, Address};
|
||||
use v1::types::Bytes;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_trace_serialize() {
|
||||
let t = Trace {
|
||||
action: Action::Call(Call {
|
||||
from: Address::from(4),
|
||||
to: Address::from(5),
|
||||
value: U256::from(6),
|
||||
gas: U256::from(7),
|
||||
input: Bytes::new(vec![0x12, 0x34]),
|
||||
}),
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: U256::from(8),
|
||||
output: Bytes::new(vec![0x56, 0x78]),
|
||||
}),
|
||||
trace_address: vec![U256::from(10)],
|
||||
subtraces: U256::from(1),
|
||||
transaction_position: U256::from(11),
|
||||
transaction_hash: H256::from(12),
|
||||
block_number: U256::from(13),
|
||||
block_hash: H256::from(14),
|
||||
};
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234"}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_action_serialize() {
|
||||
let actions = vec![Action::Call(Call {
|
||||
from: Address::from(1),
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: Bytes::new(vec![0x12, 0x34]),
|
||||
}), Action::Create(Create {
|
||||
from: Address::from(5),
|
||||
value: U256::from(6),
|
||||
gas: U256::from(7),
|
||||
init: Bytes::new(vec![0x56, 0x78]),
|
||||
})];
|
||||
|
||||
let serialized = serde_json::to_string(&actions).unwrap();
|
||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234"}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_serialize() {
|
||||
let results = vec![
|
||||
Res::Call(CallResult {
|
||||
gas_used: U256::from(1),
|
||||
output: Bytes::new(vec![0x12, 0x34]),
|
||||
}),
|
||||
Res::Create(CreateResult {
|
||||
gas_used: U256::from(2),
|
||||
code: Bytes::new(vec![0x45, 0x56]),
|
||||
address: Address::from(3),
|
||||
}),
|
||||
Res::FailedCall,
|
||||
Res::FailedCreate,
|
||||
];
|
||||
|
||||
let serialized = serde_json::to_string(&results).unwrap();
|
||||
assert_eq!(serialized, r#"[{"call":{"gasUsed":"0x01","output":"0x1234"}},{"create":{"gasUsed":"0x02","code":"0x4556","address":"0x0000000000000000000000000000000000000003"}},{"failedCall":[]},{"failedCreate":[]}]"#);
|
||||
}
|
||||
}
|
82
rpc/src/v1/types/trace_filter.rs
Normal file
82
rpc/src/v1/types/trace_filter.rs
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Trace filter deserialization.
|
||||
|
||||
use util::Address;
|
||||
use ethcore::client::BlockId;
|
||||
use ethcore::client;
|
||||
use super::BlockNumber;
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct TraceFilter {
|
||||
#[serde(rename="fromBlock")]
|
||||
pub from_block: Option<BlockNumber>,
|
||||
#[serde(rename="toBlock")]
|
||||
pub to_block: Option<BlockNumber>,
|
||||
#[serde(rename="fromAddress")]
|
||||
pub from_address: Option<Vec<Address>>,
|
||||
#[serde(rename="toAddress")]
|
||||
pub to_address: Option<Vec<Address>>,
|
||||
}
|
||||
|
||||
impl Into<client::TraceFilter> for TraceFilter {
|
||||
fn into(self) -> client::TraceFilter {
|
||||
let start = self.from_block.map_or(BlockId::Latest, Into::into);
|
||||
let end = self.to_block.map_or(BlockId::Latest, Into::into);
|
||||
client::TraceFilter {
|
||||
range: start..end,
|
||||
from_address: self.from_address.unwrap_or_else(Vec::new),
|
||||
to_address: self.to_address.unwrap_or_else(Vec::new),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use util::Address;
|
||||
use v1::types::{BlockNumber, TraceFilter};
|
||||
|
||||
#[test]
|
||||
fn test_empty_trace_filter_deserialize() {
|
||||
let s = r#"{}"#;
|
||||
let deserialized: TraceFilter = serde_json::from_str(s).unwrap();
|
||||
assert_eq!(deserialized, TraceFilter {
|
||||
from_block: None,
|
||||
to_block: None,
|
||||
from_address: None,
|
||||
to_address: None
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trace_filter_deserialize() {
|
||||
let s = r#"{
|
||||
"fromBlock": "latest",
|
||||
"toBlock": "latest",
|
||||
"fromAddress": ["0x0000000000000000000000000000000000000003"],
|
||||
"toAddress": ["0x0000000000000000000000000000000000000005"]
|
||||
}"#;
|
||||
let deserialized: TraceFilter = serde_json::from_str(s).unwrap();
|
||||
assert_eq!(deserialized, TraceFilter {
|
||||
from_block: Some(BlockNumber::Latest),
|
||||
to_block: Some(BlockNumber::Latest),
|
||||
from_address: Some(vec![Address::from(3)]),
|
||||
to_address: Some(vec![Address::from(5)]),
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user