use crate::types::{Address, BlockNumber, Bytes, H160, H256, U256};
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TraceFilter {
#[serde(rename = "fromBlock", skip_serializing_if = "Option::is_none")]
from_block: Option<BlockNumber>,
#[serde(rename = "toBlock", skip_serializing_if = "Option::is_none")]
to_block: Option<BlockNumber>,
#[serde(rename = "fromAddress", skip_serializing_if = "Option::is_none")]
from_address: Option<Vec<Address>>,
#[serde(rename = "toAddress", skip_serializing_if = "Option::is_none")]
to_address: Option<Vec<Address>>,
#[serde(skip_serializing_if = "Option::is_none")]
after: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
count: Option<usize>,
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct TraceFilterBuilder {
filter: TraceFilter,
}
impl TraceFilterBuilder {
pub fn from_block(mut self, block: BlockNumber) -> Self {
self.filter.from_block = Some(block);
self
}
pub fn to_block(mut self, block: BlockNumber) -> Self {
self.filter.to_block = Some(block);
self
}
pub fn to_address(mut self, address: Vec<H160>) -> Self {
self.filter.to_address = Some(address);
self
}
pub fn from_address(mut self, address: Vec<H160>) -> Self {
self.filter.from_address = Some(address);
self
}
pub fn after(mut self, after: usize) -> Self {
self.filter.after = Some(after);
self
}
pub fn count(mut self, count: usize) -> Self {
self.filter.count = Some(count);
self
}
pub fn build(&self) -> TraceFilter {
self.filter.clone()
}
}
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
pub struct Trace {
pub action: Action,
pub result: Option<Res>,
#[serde(rename = "traceAddress")]
pub trace_address: Vec<usize>,
pub subtraces: usize,
#[serde(rename = "transactionPosition")]
pub transaction_position: Option<usize>,
#[serde(rename = "transactionHash")]
pub transaction_hash: Option<H256>,
#[serde(rename = "blockNumber")]
pub block_number: u64,
#[serde(rename = "blockHash")]
pub block_hash: H256,
#[serde(rename = "type")]
pub action_type: ActionType,
pub error: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Res {
Call(CallResult),
Create(CreateResult),
None,
}
impl Default for Res {
fn default() -> Res {
Res::None
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(untagged, rename_all = "lowercase")]
pub enum Action {
Call(Call),
Create(Create),
Suicide(Suicide),
Reward(Reward),
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ActionType {
Call,
Create,
Suicide,
Reward,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct CallResult {
#[serde(rename = "gasUsed")]
pub gas_used: U256,
pub output: Bytes,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct CreateResult {
#[serde(rename = "gasUsed")]
pub gas_used: U256,
pub code: Bytes,
pub address: Address,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct Call {
pub from: Address,
pub to: Address,
pub value: U256,
pub gas: U256,
pub input: Bytes,
#[serde(rename = "callType")]
pub call_type: CallType,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum CallType {
#[serde(rename = "none")]
None,
#[serde(rename = "call")]
Call,
#[serde(rename = "callcode")]
CallCode,
#[serde(rename = "delegatecall")]
DelegateCall,
#[serde(rename = "staticcall")]
StaticCall,
}
impl Default for CallType {
fn default() -> CallType {
CallType::None
}
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct Create {
pub from: Address,
pub value: U256,
pub gas: U256,
pub init: Bytes,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct Suicide {
pub address: Address,
#[serde(rename = "refundAddress")]
pub refund_address: Address,
pub balance: U256,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Reward {
pub author: Address,
pub value: U256,
#[serde(rename = "rewardType")]
pub reward_type: RewardType,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum RewardType {
#[serde(rename = "block")]
Block,
#[serde(rename = "uncle")]
Uncle,
#[serde(rename = "emptyStep")]
EmptyStep,
#[serde(rename = "external")]
External,
}
#[cfg(test)]
mod tests {
use super::*;
const EXAMPLE_TRACE_CALL: &str = r#"{
"action": {
"callType": "call",
"from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"gas": "0x63ab9",
"input": "0xb9f256cd000000000000000000000000fb6916095ca1df60bb79ce92ce3ea74c37c5d3590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000e85468697320697320746865206f6666696369616c20457468657265756d20466f756e646174696f6e20546970204a61722e20466f722065766572792061626f76652061206365727461696e2076616c756520646f6e6174696f6e207765276c6c2063726561746520616e642073656e6420746f20796f752061206272616e64206e657720556e69636f726e20546f6b656e2028f09fa684292e20436865636b2074686520756e69636f726e2070726963652062656c6f77202831206574686572203d20313030302066696e6e6579292e205468616e6b7320666f722074686520737570706f72742100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to": "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359",
"value": "0x0"
},
"blockHash": "0x6474a53a9ebf72d306a1406ec12ded12e210b6c3141b4373bfb3a3cea987dfb8",
"blockNumber": 988775,
"result": {
"gasUsed": "0x4b419",
"output": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"subtraces": 1,
"traceAddress": [],
"transactionHash": "0x342c284238149db221f9d87db87f90ffad7ac0aac57c0c480142f4c21b63f652",
"transactionPosition": 1,
"type": "call"
}"#;
const EXAMPLE_TRACE_CREATE: &str = r#"{
"action": {
"from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"gas": "0x63ab9",
"init": "0xb9f256cd000000000000000000000000fb6916095ca1df60bb79ce92ce3ea74c37c5d3590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000e85468697320697320746865206f6666696369616c20457468657265756d20466f756e646174696f6e20546970204a61722e20466f722065766572792061626f76652061206365727461696e2076616c756520646f6e6174696f6e207765276c6c2063726561746520616e642073656e6420746f20796f752061206272616e64206e657720556e69636f726e20546f6b656e2028f09fa684292e20436865636b2074686520756e69636f726e2070726963652062656c6f77202831206574686572203d20313030302066696e6e6579292e205468616e6b7320666f722074686520737570706f72742100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"value": "0x0"
},
"blockHash": "0x6474a53a9ebf72d306a1406ec12ded12e210b6c3141b4373bfb3a3cea987dfb8",
"blockNumber": 988775,
"result": {
"gasUsed": "0x4b419",
"output": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"subtraces": 1,
"traceAddress": [],
"transactionHash": "0x342c284238149db221f9d87db87f90ffad7ac0aac57c0c480142f4c21b63f652",
"transactionPosition": 1,
"type": "create"
}"#;
const EXAMPLE_TRACE_SUICIDE: &str = r#"{
"action": {
"address": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"refundAddress": "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359",
"balance": "0x0"
},
"blockHash": "0x6474a53a9ebf72d306a1406ec12ded12e210b6c3141b4373bfb3a3cea987dfb8",
"blockNumber": 988775,
"result": {
"gasUsed": "0x4b419",
"output": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"subtraces": 1,
"traceAddress": [],
"transactionHash": "0x342c284238149db221f9d87db87f90ffad7ac0aac57c0c480142f4c21b63f652",
"transactionPosition": 1,
"type": "suicide"
}"#;
const EXAMPLE_TRACE_REWARD: &str = r#"{
"action": {
"author": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"value": "0x0",
"rewardType": "block"
},
"blockHash": "0x6474a53a9ebf72d306a1406ec12ded12e210b6c3141b4373bfb3a3cea987dfb8",
"blockNumber": 988775,
"result": {
"gasUsed": "0x4b419",
"output": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"subtraces": 1,
"traceAddress": [],
"transactionHash": "0x342c284238149db221f9d87db87f90ffad7ac0aac57c0c480142f4c21b63f652",
"transactionPosition": 1,
"type": "reward"
}"#;
#[test]
fn test_deserialize_trace() {
let _trace: Trace = serde_json::from_str(EXAMPLE_TRACE_CALL).unwrap();
let _trace: Trace = serde_json::from_str(EXAMPLE_TRACE_CREATE).unwrap();
let _trace: Trace = serde_json::from_str(EXAMPLE_TRACE_SUICIDE).unwrap();
let _trace: Trace = serde_json::from_str(EXAMPLE_TRACE_REWARD).unwrap();
}
}