Skip to content

Commit

Permalink
Add traces namespace (#148)
Browse files Browse the repository at this point in the history
* Add `traces` namespace

basic code for traces namespace and types

tests for traces and trace_filtering types
builder for Trace Filter

tests for `traces` namespace and traces types (traces + trace_filtering)

move ValueOrArray back

* Add `traces` namespace

basic code for traces namespace and types

tests for traces and trace_filtering types
builder for Trace Filter

tests for `traces` namespace and traces types (traces + trace_filtering)

* fix return type of `trace_get`

* Fix types for Addresses
Some addresses were usize, some were H160.
This changes all addresses in `traces` to be `Address`

* make blockNumber and blockHash optional in TransactionReceipt (#164)

* Derive Eq and Hash for Bytes (#168)

This just forwards to the implementation of Vec.

* Fix build with OpenSSL 1.1.1 (#170)

* Fix build with OpenSSL 1.1.1
Update hyper to 0.12
Update hyper-tls to 0.3
update websocket to 0.21
Update http.rs to new hyper 0.12 API
bump version

* fix comment placement

* Revise `Traces` namespace
remove custom deserialize, switch to untagged serde representation
  • Loading branch information
insipx authored and tomusdrw committed Nov 13, 2018
1 parent 4d6c6d7 commit 86ca0f1
Show file tree
Hide file tree
Showing 6 changed files with 2,906 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod eth_filter;
mod eth_subscribe;
mod net;
mod personal;
mod traces;
mod web3;

pub use self::eth::Eth;
Expand All @@ -13,6 +14,7 @@ pub use self::eth_subscribe::{SubscriptionId, SubscriptionStream};
pub use self::net::Net;
pub use self::personal::Personal;
pub use self::web3::Web3 as Web3Api;
pub use self::traces::Traces;

use std::time::Duration;
use futures::IntoFuture;
Expand Down Expand Up @@ -75,6 +77,11 @@ impl<T: Transport> Web3<T> {
self.api()
}

/// Access methods from `trace` namespace
pub fn trace(&self) -> traces::Traces<T> {
self.api()
}

/// Should be used to wait for confirmations
pub fn wait_for_confirmations<F, V>(&self, poll_interval: Duration, confirmations: usize, check: V) -> confirm::Confirmations<T, V, F::Future>
where
Expand Down
233 changes: 233 additions & 0 deletions src/api/traces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
use api::Namespace;
use helpers::{self, CallFuture};
use types::{TraceType, BlockTrace, Trace, TraceFilter, CallRequest, BlockNumber, Bytes, H256, Index};
use Transport;

/// `Trace` namespace
#[derive(Debug, Clone)]
pub struct Traces<T> {
transport: T,
}

impl<T: Transport> Namespace<T> for Traces<T> {
fn new(transport: T) -> Self
where
Self: Sized,
{
Traces { transport }
}

fn transport(&self) -> &T {
&self.transport
}
}
impl<T: Transport> Traces<T> {
/// Executes the given call and returns a number of possible traces for it
pub fn call(&self, req: CallRequest, trace_type: Vec<TraceType>, block: Option<BlockNumber>) -> CallFuture<BlockTrace, T::Out> {
let req = helpers::serialize(&req);
let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
let trace_type = helpers::serialize(&trace_type);
CallFuture::new(self.transport.execute("trace_call", vec![req, trace_type, block]))
}

/// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces
pub fn raw_transaction(&self, data: Bytes, trace_type: Vec<TraceType>) -> CallFuture<BlockTrace, T::Out> {
let data = helpers::serialize(&data);
let trace_type = helpers::serialize(&trace_type);
CallFuture::new(self.transport.execute("trace_rawTransaction", vec![data, trace_type]))
}

/// Replays a transaction, returning the traces
pub fn replay_transaction(&self, hash: H256, trace_type: Vec<TraceType>) -> CallFuture<BlockTrace, T::Out> {
let hash = helpers::serialize(&hash);
let trace_type = helpers::serialize(&trace_type);
CallFuture::new(self.transport.execute("trace_replayTransaction", vec![hash, trace_type]))
}

/// Replays all transactions in a block returning the requested traces for each transaction
pub fn replay_block_transactions(&self, block: BlockNumber, trace_type: Vec<TraceType>) -> CallFuture<BlockTrace, T::Out> {
let block = helpers::serialize(&block);
let trace_type = helpers::serialize(&trace_type);
CallFuture::new(self.transport.execute("trace_replayBlockTransaction", vec![block, trace_type]))
}

/// Returns traces created at given block
pub fn block(&self, block: BlockNumber) -> CallFuture<Vec<Trace>, T::Out> {
let block = helpers::serialize(&block);
CallFuture::new(self.transport.execute("trace_block", vec![block]))
}

/// Return traces matching the given filter
///
/// See [TraceFilterBuilder](../types/struct.TraceFilterBuilder.html)
pub fn filter(&self, filter: TraceFilter) -> CallFuture<Vec<Trace>, T::Out> {
let filter = helpers::serialize(&filter);
CallFuture::new(self.transport.execute("trace_filter", vec![filter]))
}

/// Returns trace at the given position
pub fn get(&self, hash: H256, index: Vec<Index>) -> CallFuture<Trace, T::Out> {
let hash = helpers::serialize(&hash);
let index = helpers::serialize(&index);
CallFuture::new(self.transport.execute("trace_get", vec![hash, index]))
}

/// Returns all traces of a given transaction
pub fn transaction(&self, hash: H256) -> CallFuture<Vec<Trace>, T::Out> {
let hash = helpers::serialize(&hash);
CallFuture::new(self.transport.execute("trace_transaction", vec![hash]))
}
}

#[cfg(test)]
mod tests {
use futures::Future;

use api::Namespace;
use types::{TraceType, BlockNumber, BlockTrace, Trace, TraceFilterBuilder, Bytes, CallRequest, H256};

use super::Traces;

const EXAMPLE_BLOCKTRACE: &'static str = r#"
{
"output": "0x010203",
"stateDiff": null,
"trace": [
{
"action": {
"callType": "call",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x1dcd12f8",
"input": "0x",
"to": "0x0000000000000000000000000000000000000123",
"value": "0x1"
},
"result": {
"gasUsed": "0x0",
"output": "0x"
},
"subtraces": 0,
"traceAddress": [],
"type": "call"
}
],
"vmTrace": null
}
"#;

const EXAMPLE_TRACE_ARR: &'static str = r#"
[
{
"action": {
"callType": "call",
"from": "0xaa7b131dc60b80d3cf5e59b5a21a666aa039c951",
"gas": "0x0",
"input": "0x",
"to": "0xd40aba8166a212d6892125f079c33e6f5ca19814",
"value": "0x4768d7effc3fbe"
},
"blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
"blockNumber": 3068185,
"result": {
"gasUsed": "0x0",
"output": "0x"
},
"subtraces": 0,
"traceAddress": [],
"transactionHash": "0x07da28d752aba3b9dd7060005e554719c6205c8a3aea358599fc9b245c52f1f6",
"transactionPosition": 0,
"type": "call"
}
]
"#;

const EXAMPLE_TRACE: &'static str = r#"
{
"action": {
"callType": "call",
"from": "0xaa7b131dc60b80d3cf5e59b5a21a666aa039c951",
"gas": "0x0",
"input": "0x",
"to": "0xd40aba8166a212d6892125f079c33e6f5ca19814",
"value": "0x4768d7effc3fbe"
},
"blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
"blockNumber": 3068185,
"result": {
"gasUsed": "0x0",
"output": "0x"
},
"subtraces": 0,
"traceAddress": [],
"transactionHash": "0x07da28d752aba3b9dd7060005e554719c6205c8a3aea358599fc9b245c52f1f6",
"transactionPosition": 0,
"type": "call"
}
"#;

rpc_test! (
Traces:call, CallRequest {
from: None, to: 0x123.into(),
gas: None, gas_price: None,
value: Some(0x1.into()), data: None,
}, vec![TraceType::Trace], None
=>
"trace_call", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#"["trace"]"#, r#""latest""#];
::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
=> ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
);

rpc_test!(
Traces:raw_transaction, Bytes(vec![1, 2, 3, 4]), vec![TraceType::Trace]
=>
"trace_rawTransaction", vec![r#""0x01020304""#, r#"["trace"]"#];
::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
=> ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
);

rpc_test!(
Traces:replay_transaction, H256::from("0x0000000000000000000000000000000000000000000000000000000000000123"), vec![TraceType::Trace]
=>
"trace_replayTransaction", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#,r#"["trace"]"#];
::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
=> ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
);

rpc_test!(
Traces:replay_block_transactions, BlockNumber::Latest, vec![TraceType::Trace]
=>
"trace_replayBlockTransaction", vec![r#""latest""#, r#"["trace"]"#];
::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
=> ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
);

rpc_test!(
Traces:block, BlockNumber::Latest
=>
"trace_block", vec![r#""latest""#];
::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
=> ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
);

rpc_test!(
Traces:filter, TraceFilterBuilder::default().build() => "trace_filter", vec!["{}"];
::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
=> ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
);

rpc_test!(
Traces:get, H256::from("0x0000000000000000000000000000000000000000000000000000000000000123"), vec![0.into()]
=>
"trace_get", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#"["0x0"]"#];
::serde_json::from_str(EXAMPLE_TRACE).unwrap()
=> ::serde_json::from_str::<Trace>(EXAMPLE_TRACE).unwrap()
);

rpc_test!(
Traces:transaction, H256::from("0x0000000000000000000000000000000000000000000000000000000000000123")
=>
"trace_transaction", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
=> ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
);
}

0 comments on commit 86ca0f1

Please sign in to comment.