Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix result of debug_traceBlockByNumber #3060

Merged
merged 12 commits into from
Nov 29, 2024
20 changes: 14 additions & 6 deletions client/evm-tracing/src/formatters/call_tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::listeners::call_list::Listener;
use crate::types::serialization::*;
use serde::Serialize;

use crate::types::block::BlockTransactionTrace;
use ethereum_types::{H160, U256};
use parity_scale_codec::{Decode, Encode};
use sp_std::{cmp::Ordering, vec::Vec};
Expand All @@ -33,14 +34,14 @@ pub struct Formatter;

impl super::ResponseFormatter for Formatter {
type Listener = Listener;
type Response = Vec<TransactionTrace>;
type Response = Vec<BlockTransactionTrace>;

fn format(mut listener: Listener) -> Option<Vec<TransactionTrace>> {
fn format(mut listener: Listener) -> Option<Vec<BlockTransactionTrace>> {
// Remove empty BTreeMaps pushed to `entries`.
// I.e. InvalidNonce or other pallet_evm::runner exits
listener.entries.retain(|x| !x.is_empty());
let mut traces = Vec::new();
for entry in listener.entries.iter() {
for (eth_tx_index, entry) in listener.entries.iter().enumerate() {
let mut result: Vec<Call> = entry
.into_iter()
.map(|(_, it)| {
Expand Down Expand Up @@ -241,9 +242,16 @@ impl super::ResponseFormatter for Formatter {
*trace_address = None;
}
if result.len() == 1 {
traces.push(TransactionTrace::CallListNested(result.pop().expect(
"result.len() == 1, so pop() necessarily returns this element",
)));
traces.push(BlockTransactionTrace {
tx_position: eth_tx_index as u32,
// Use default, the correct value will be set upstream
tx_hash: Default::default(),
result: TransactionTrace::CallListNested(
result
.pop()
.expect("result.len() == 1, so pop() necessarily returns this element"),
),
});
}
}
if traces.is_empty() {
Expand Down
11 changes: 11 additions & 0 deletions client/evm-tracing/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ use ethereum_types::{H160, H256, U256};
use parity_scale_codec::{Decode, Encode};
use sp_std::vec::Vec;

/// Block transaction trace.
#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockTransactionTrace {
RomarQ marked this conversation as resolved.
Show resolved Hide resolved
#[serde(serialize_with = "h256_0x_serialize")]
pub tx_hash: H256,
pub result: crate::types::single::TransactionTrace,
#[serde(skip_serializing)]
pub tx_position: u32,
}

#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionTrace {
Expand Down
4 changes: 2 additions & 2 deletions client/rpc-core/debug/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use ethereum::AccessListItem;
use ethereum_types::{H160, H256, U256};
use fc_rpc_core::types::Bytes;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use moonbeam_client_evm_tracing::types::single;
use moonbeam_client_evm_tracing::types::{block, single};
use moonbeam_rpc_core_types::RequestBlockId;
use serde::Deserialize;

Expand Down Expand Up @@ -83,5 +83,5 @@ pub trait Debug {
&self,
id: RequestBlockId,
params: Option<TraceParams>,
) -> RpcResult<Vec<single::TransactionTrace>>;
) -> RpcResult<Vec<block::BlockTransactionTrace>>;
}
37 changes: 29 additions & 8 deletions client/rpc/debug/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use ethereum_types::H256;
use fc_rpc::{frontier_backend_client, internal_err};
use fc_storage::StorageOverride;
use fp_rpc::EthereumRuntimeRPCApi;
use moonbeam_client_evm_tracing::types::block;
use moonbeam_client_evm_tracing::types::block::BlockTransactionTrace;
use moonbeam_client_evm_tracing::{formatters::ResponseFormatter, types::single};
use moonbeam_rpc_core_types::{RequestBlockId, RequestBlockTag};
use moonbeam_rpc_primitives_debug::{DebugRuntimeApi, TracerInput};
Expand All @@ -40,6 +42,7 @@ use sp_runtime::{
generic::BlockId,
traits::{BlakeTwo256, Block as BlockT, Header as HeaderT, UniqueSaturatedInto},
};
use std::collections::BTreeMap;
use std::{future::Future, marker::PhantomData, sync::Arc};

pub enum RequesterInput {
Expand All @@ -50,7 +53,7 @@ pub enum RequesterInput {

pub enum Response {
Single(single::TransactionTrace),
Block(Vec<single::TransactionTrace>),
Block(Vec<block::BlockTransactionTrace>),
}

pub type Responder = oneshot::Sender<RpcResult<Response>>;
Expand Down Expand Up @@ -102,7 +105,7 @@ impl DebugServer for Debug {
&self,
id: RequestBlockId,
params: Option<TraceParams>,
) -> RpcResult<Vec<single::TransactionTrace>> {
) -> RpcResult<Vec<BlockTransactionTrace>> {
let requester = self.requester.clone();

let (tx, rx) = oneshot::channel();
Expand Down Expand Up @@ -420,7 +423,12 @@ where
.unwrap_or_default();

// Known ethereum transaction hashes.
let eth_tx_hashes: Vec<_> = statuses.iter().map(|t| t.transaction_hash).collect();
let eth_transactions_by_index: BTreeMap<u32, H256> = statuses
.iter()
.map(|t| (t.transaction_index, t.transaction_hash))
.collect();

let eth_tx_hashes: Vec<_> = eth_transactions_by_index.values().cloned().collect();

// If there are no ethereum transactions in the block return empty trace right away.
if eth_tx_hashes.is_empty() {
Expand Down Expand Up @@ -504,9 +512,22 @@ where
proxy.finish_transaction();
let response = match tracer_input {
TracerInput::CallTracer => {
moonbeam_client_evm_tracing::formatters::CallTracer::format(proxy)
.ok_or("Trace result is empty.")
.map_err(|e| internal_err(format!("{:?}", e)))
let result =
moonbeam_client_evm_tracing::formatters::CallTracer::format(proxy)
.ok_or("Trace result is empty.")
.map_err(|e| internal_err(format!("{:?}", e)))?
.into_iter()
.map(|mut trace| {
if let Some(transaction_hash) =
eth_transactions_by_index.get(&trace.tx_position)
{
trace.tx_hash = *transaction_hash;
}
trace
})
.collect::<Vec<BlockTransactionTrace>>();

Ok(result)
}
_ => Err(internal_err(
"Bug: failed to resolve the tracer format.".to_string(),
Expand Down Expand Up @@ -725,7 +746,7 @@ where
)
.ok_or("Trace result is empty.")
.map_err(|e| internal_err(format!("{:?}", e)))?;
Ok(res.pop().expect("Trace result is empty."))
Ok(res.pop().expect("Trace result is empty.").result)
}
_ => Err(internal_err(
"Bug: failed to resolve the tracer format.".to_string(),
Expand Down Expand Up @@ -945,7 +966,7 @@ where
moonbeam_client_evm_tracing::formatters::CallTracer::format(proxy)
.ok_or("Trace result is empty.")
.map_err(|e| internal_err(format!("{:?}", e)))?;
Ok(res.pop().expect("Trace result is empty."))
Ok(res.pop().expect("Trace result is empty.").result)
}
_ => Err(internal_err(
"Bug: failed to resolve the tracer format.".to_string(),
Expand Down
10 changes: 5 additions & 5 deletions test/suites/tracing-tests/test-trace-5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ describeSuite({
{ tracer: "callTracer" },
]);
expect(block.transactions.length).to.be.equal(traceTx.length);
traceTx.forEach((trace: { [key: string]: any }) => {
expect(trace.calls.length).to.be.equal(1);
expect(Object.keys(trace).sort()).to.deep.equal([
traceTx.forEach((trace: { [key: string]: any }, index) => {
expect(trace.txHash).to.be.equal(block.transactions[index]);
expect(trace.result.calls.length).to.be.equal(1);
expect(Object.keys(trace.result).sort()).to.deep.equal([
"calls",
"from",
"gas",
Expand All @@ -136,8 +137,7 @@ describeSuite({
]);
expect(block.transactions.length).to.be.equal(traceTx.length);
traceTx.forEach((trace: { [key: string]: any }) => {
expect(trace.calls.length).to.be.equal(1);
expect(Object.keys(trace).sort()).to.deep.equal([
expect(Object.keys(trace.result).sort()).to.deep.equal([
"calls",
"from",
"gas",
Expand Down
14 changes: 8 additions & 6 deletions test/suites/tracing-tests/test-trace-ethereum-xcm-2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,17 @@ describeSuite({
// 1st transaction is regular ethereum transaction.
// - `From` is Alith's adddress.
// - `To` is the ethereum contract address.
expect(trace[0].from).to.eq(alith.address.toLowerCase());
expect(trace[0].to).to.eq(ethContractAddress.toLowerCase());
expect(trace[0].type).be.eq("CREATE");
const call = trace[0].result;
expect(call.from).to.eq(alith.address.toLowerCase());
expect(call.to).to.eq(ethContractAddress.toLowerCase());
expect(call.type).be.eq("CREATE");
// 2nd transaction is xcm.
// - `From` is the descended origin.
// - `To` is the xcm contract address.
expect(trace[1].from).to.eq(ethereumXcmDescendedOrigin.toLowerCase());
expect(trace[1].to).to.eq(xcmContractAddress.toLowerCase());
expect(trace[1].type).to.eq("CALL");
const call2 = trace[1].result;
expect(call2.from).to.eq(ethereumXcmDescendedOrigin.toLowerCase());
expect(call2.to).to.eq(xcmContractAddress.toLowerCase());
expect(call2.type).to.eq("CALL");
},
});
},
Expand Down
Loading