Skip to content

Commit

Permalink
test: update testing for Trace (kkrt-labs#1318)
Browse files Browse the repository at this point in the history
* feat: update_testing_for_trace

* fix: lint

* fix: lint

* fix: clone TracerBuilder
  • Loading branch information
eugypalu authored Jul 31, 2024
1 parent f70b215 commit 836e04e
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 189 deletions.
6 changes: 3 additions & 3 deletions src/tracing/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use reth_rpc_types::{
};
use revm_inspectors::tracing::TracingInspectorConfig;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Floating;
#[derive(Debug)]
pub struct Pinned;
Expand Down Expand Up @@ -87,8 +87,8 @@ impl From<GethDebugTracingCallOptions> for TracingOptions {
}
}

#[derive(Debug)]
pub struct TracerBuilder<P: EthereumProvider + Send + Sync, Status = Floating> {
#[derive(Debug, Clone)]
pub struct TracerBuilder<P: EthereumProvider + Send + Sync + Clone, Status = Floating> {
eth_provider: P,
env: Env,
block: Block,
Expand Down
1 change: 1 addition & 0 deletions tests/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ pub mod debug_api;
pub mod eth_provider;
pub mod kakarot_api;
pub mod trace_api;
pub mod tracer;
pub mod txpool_api;
191 changes: 5 additions & 186 deletions tests/tests/trace_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,17 @@ use kakarot_rpc::{
rpc::{start_kakarot_rpc_server, RawRpcParamsBuilder},
},
};
use reth_primitives::{Address, BlockId, Bytes, TxKind, B256, U256};
use reth_primitives::{Address, BlockId, TxKind, B256, U256};
use reth_rpc_types::{
request::TransactionInput,
trace::{
geth::{
CallFrame, GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingCallOptions,
GethDebugTracingOptions, GethTrace, TraceResult,
},
parity::{Action, CallAction, CallOutput, CallType, LocalizedTransactionTrace, TraceOutput, TransactionTrace},
trace::geth::{
CallFrame, GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingCallOptions,
GethDebugTracingOptions, GethTrace,
},
OtherFields, TransactionRequest,
};
use rstest::*;
use serde_json::{json, Value};
use serde_json::Value;
use starknet::{core::types::MaybePendingBlockWithTxHashes, providers::Provider};

/// The block number on which tracing will be performed.
Expand Down Expand Up @@ -129,184 +126,6 @@ pub async fn tracing(
katana.add_transactions_with_header_to_database(txs, header).await;
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_trace_block(#[future] plain_opcodes: (Katana, KakarotEvmContract), _setup: ()) {
// Setup the Kakarot RPC server.
let katana = plain_opcodes.0;
let plain_opcodes = plain_opcodes.1;
tracing(&katana, &plain_opcodes, "createCounterAndInvoke", Box::new(|_| vec![])).await;

let (server_addr, server_handle) =
start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server");

// Send the trace_block RPC request.
let reqwest_client = reqwest::Client::new();
let res = reqwest_client
.post(format!("http://localhost:{}", server_addr.port()))
.header("Content-Type", "application/json")
.body(RawRpcParamsBuilder::new("trace_block").add_param(format!("0x{TRACING_BLOCK_NUMBER:016x}")).build())
.send()
.await
.expect("Failed to call Debug RPC");
let response = res.text().await.expect("Failed to get response body");
let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body");
let traces: Option<Vec<LocalizedTransactionTrace>> =
serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result");

// Assert that traces is not None, meaning the response contains some traces.
assert!(traces.is_some());
// We expect 3 traces per transaction: CALL, CREATE, and CALL.
// Except for the last one which is out of resources.
assert!(traces.clone().unwrap().len() == 3 * (TRACING_TRANSACTIONS_COUNT - 1) + 1);

// Get the last trace from the trace vector, which is expected to be out of resources.
let trace_vec = traces.unwrap();
let out_of_resources_trace = trace_vec.last().unwrap();

// Assert that the block number of the out-of-resources trace is equal to the expected TRACING_BLOCK_NUMBER.
assert_eq!(out_of_resources_trace.clone().block_number, Some(TRACING_BLOCK_NUMBER));
// Assert that the trace matches the expected default TransactionTrace.
assert_eq!(
out_of_resources_trace.trace,
TransactionTrace {
action: Action::Call(CallAction {
from: Address::ZERO,
call_type: CallType::Call,
gas: Default::default(),
input: Bytes::default(),
to: Address::ZERO,
value: U256::ZERO
}),
error: None,
result: Some(TraceOutput::Call(CallOutput { gas_used: Default::default(), output: Bytes::default() })),
subtraces: 0,
trace_address: vec![],
}
);

drop(server_handle);
}

async fn trace_block_by_number(port: u16) -> Vec<TraceResult> {
let reqwest_client = reqwest::Client::new();
let res = reqwest_client
.post(format!("http://localhost:{port}"))
.header("Content-Type", "application/json")
.body(
RawRpcParamsBuilder::new("debug_traceBlockByNumber")
.add_param(format!("0x{TRACING_BLOCK_NUMBER:016x}"))
.add_param(json!({
"tracer": "callTracer",
"tracerConfig": {
"onlyTopCall": false
},
"timeout": "300s"
}))
.build(),
)
.send()
.await
.expect("Failed to call Debug RPC");
let response = res.text().await.expect("Failed to get response body");
let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body");

serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result")
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_debug_trace_block_by_number(#[future] plain_opcodes: (Katana, KakarotEvmContract), _setup: ()) {
// Setup the Kakarot RPC server.
let katana = plain_opcodes.0;
let plain_opcodes = plain_opcodes.1;
tracing(&katana, &plain_opcodes, "createCounterAndInvoke", Box::new(|_| vec![])).await;

let (server_addr, server_handle) =
start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server");

// Send the trace_block RPC request.
let traces = trace_block_by_number(server_addr.port()).await;

// We expect 1 trace per transaction given the formatting of the debug_traceBlockByNumber response.
assert!(traces.len() == TRACING_TRANSACTIONS_COUNT);
drop(server_handle);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
async fn test_debug_trace_transaction(#[future] plain_opcodes: (Katana, KakarotEvmContract), _setup: ()) {
// Setup the Kakarot RPC server.
let katana = plain_opcodes.0;
let plain_opcodes = plain_opcodes.1;
tracing(&katana, &plain_opcodes, "createCounterAndInvoke", Box::new(|_| vec![])).await;

let (server_addr, server_handle) =
start_kakarot_rpc_server(&katana).await.expect("Error setting up Kakarot RPC server");

// Get the block in order to trace a transaction.
let block = katana
.eth_provider()
.block_by_number(TRACING_BLOCK_NUMBER.into(), false)
.await
.expect("Failed to get block")
.unwrap();
let index = TRACING_TRANSACTIONS_COUNT - 2;
let tx_hash = block.transactions.as_hashes().unwrap().get(index).unwrap();

// Send the trace_block RPC request.
let reqwest_client = reqwest::Client::new();
let res = reqwest_client
.post(format!("http://localhost:{}", server_addr.port()))
.header("Content-Type", "application/json")
.body(
RawRpcParamsBuilder::new("debug_traceTransaction")
.add_param(format!("0x{tx_hash:016x}"))
.add_param(json!({
"tracer": "callTracer",
"tracerConfig": {
"onlyTopCall": false
},
"timeout": "300s"
}))
.build(),
)
.send()
.await
.expect("Failed to call Debug RPC");
let response = res.text().await.expect("Failed to get response body");
let raw: Value = serde_json::from_str(&response).expect("Failed to deserialize response body");
let trace: GethTrace = serde_json::from_value(raw["result"].clone()).expect("Failed to deserialize result");

// Get the traces for the block
let traces = trace_block_by_number(server_addr.port()).await;
let reth_rpc_types::trace::geth::TraceResult::Success { result: expected_trace, .. } =
traces.get(index).cloned().unwrap()
else {
panic!("Failed to get expected trace")
};

// Compare traces
assert_eq!(expected_trace, trace);

// Get the last trace from the trace vector, which is expected to be out of resources.
let run_out_of_resource_trace = traces.last().unwrap();

// Asser that the trace matches the expected default GethTrace for a transaction that runs out of resources.
match run_out_of_resource_trace {
TraceResult::Success { result, .. } => assert_eq!(
*result,
GethTrace::Default(reth_rpc_types::trace::geth::DefaultFrame { failed: true, ..Default::default() })
),
TraceResult::Error { .. } => panic!("Expected a success trace result"),
};

drop(server_handle);
}

#[rstest]
#[awt]
#[tokio::test(flavor = "multi_thread")]
Expand Down
Loading

0 comments on commit 836e04e

Please sign in to comment.