diff --git a/core/lib/types/src/api/mod.rs b/core/lib/types/src/api/mod.rs index 26a6230be613..2aa5d55529e8 100644 --- a/core/lib/types/src/api/mod.rs +++ b/core/lib/types/src/api/mod.rs @@ -600,7 +600,7 @@ pub struct GetLogsFilter { #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct ResultDebugCall { - pub result: CallTracerResult, + pub result: DebugCall, } #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] @@ -734,18 +734,18 @@ pub enum BlockStatus { /// FlatTracer is always more than one trace, so when we have to trace one transaction it also appeared as many traces #[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase", untagged)] +#[serde(untagged)] pub enum CallTracerResult { - CallTrace(DebugCall), - FlattCallTrace(Box>), + CallTrace(ResultDebugCall), + FlattCallTrace(Vec), } /// For tracing blocks we need to have all traces being combined all together without separation. #[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase", untagged)] +#[serde(untagged)] pub enum CallTracerOption { CallTrace(DebugCall), - FlattCallTrace(Box), + FlattCallTrace(Vec), } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/core/lib/web3_decl/src/namespaces/debug.rs b/core/lib/web3_decl/src/namespaces/debug.rs index 34372241e847..16e9a431f1f9 100644 --- a/core/lib/web3_decl/src/namespaces/debug.rs +++ b/core/lib/web3_decl/src/namespaces/debug.rs @@ -25,14 +25,14 @@ pub trait DebugNamespace { &self, block: BlockNumber, options: Option, - ) -> RpcResult>; + ) -> RpcResult>; #[method(name = "traceBlockByHash")] async fn trace_block_by_hash( &self, hash: H256, options: Option, - ) -> RpcResult>; + ) -> RpcResult>; #[method(name = "traceCall")] async fn trace_call( @@ -40,12 +40,12 @@ pub trait DebugNamespace { request: CallRequest, block: Option, options: Option, - ) -> RpcResult; + ) -> RpcResult; #[method(name = "traceTransaction")] async fn trace_transaction( &self, tx_hash: H256, options: Option, - ) -> RpcResult>; + ) -> RpcResult>; } diff --git a/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs b/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs index 94f3823dea6d..3696c6b5d7c7 100644 --- a/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs +++ b/core/node/api_server/src/web3/backend_jsonrpsee/namespaces/debug.rs @@ -16,7 +16,7 @@ impl DebugNamespaceServer for DebugNamespace { &self, block: BlockNumber, options: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.debug_trace_block_impl(BlockId::Number(block), options) .await .map_err(|err| self.current_method().map_err(err)) @@ -26,7 +26,7 @@ impl DebugNamespaceServer for DebugNamespace { &self, hash: H256, options: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.debug_trace_block_impl(BlockId::Hash(hash), options) .await .map_err(|err| self.current_method().map_err(err)) @@ -37,7 +37,7 @@ impl DebugNamespaceServer for DebugNamespace { request: CallRequest, block: Option, options: Option, - ) -> RpcResult { + ) -> RpcResult { self.debug_trace_call_impl(request, block, options) .await .map_err(|err| self.current_method().map_err(err)) @@ -47,7 +47,7 @@ impl DebugNamespaceServer for DebugNamespace { &self, tx_hash: H256, options: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.debug_trace_transaction_impl(tx_hash, options) .await .map_err(|err| self.current_method().map_err(err)) diff --git a/core/node/api_server/src/web3/namespaces/debug.rs b/core/node/api_server/src/web3/namespaces/debug.rs index 218d056e73be..3f67f5a2cff0 100644 --- a/core/node/api_server/src/web3/namespaces/debug.rs +++ b/core/node/api_server/src/web3/namespaces/debug.rs @@ -10,7 +10,7 @@ use zksync_system_constants::MAX_ENCODED_TX_SIZE; use zksync_types::{ api::{ BlockId, BlockNumber, CallTracerOption, CallTracerResult, DebugCall, DebugCallType, - SupportedTracers, TracerConfig, + ResultDebugCall, SupportedTracers, TracerConfig, }, debug_flat_call::{Action, CallResult, DebugCallFlat}, fee_model::BatchFeeInput, @@ -58,7 +58,7 @@ impl DebugNamespace { index: usize, transaction_hash: H256, tracer_option: Option, - ) -> CallTracerResult { + ) -> CallTracerOption { let (only_top_call, flatten) = tracer_option .map(|options| { ( @@ -78,9 +78,9 @@ impl DebugNamespace { index, transaction_hash, ); - CallTracerResult::FlattCallTrace(Box::new(calls)) + CallTracerOption::FlattCallTrace(calls) } else { - CallTracerResult::CallTrace(Self::map_default_call(call, only_top_call)) + CallTracerOption::CallTrace(Self::map_default_call(call, only_top_call)) } } pub(crate) fn map_default_call(call: Call, only_top_call: bool) -> DebugCall { @@ -183,7 +183,7 @@ impl DebugNamespace { &self, block_id: BlockId, options: Option, - ) -> Result, Web3Error> { + ) -> Result, Web3Error> { self.current_method().set_block_id(block_id); if matches!(block_id, BlockId::Number(BlockNumber::Pending)) { // See `EthNamespace::get_block_impl()` for an explanation why this check is needed. @@ -200,30 +200,31 @@ impl DebugNamespace { .get_traces_for_l2_block(block_number) .await .map_err(DalError::generalize)?; - let call_trace = call_traces - .into_iter() - .flat_map(|(call_trace, hash, index)| { - match Self::map_call(call_trace, index, hash, options) { - CallTracerResult::CallTrace(call) => { - vec![CallTracerOption::CallTrace(call)] - } - CallTracerResult::FlattCallTrace(call) => call - .into_iter() - .map(Box::new) - .map(CallTracerOption::FlattCallTrace) - .collect(), + + let mut calls = vec![]; + let mut flat_calls = vec![]; + for (call_trace, hash, index) in call_traces { + match Self::map_call(call_trace, index, hash, options) { + CallTracerOption::CallTrace(call) => { + calls.push(CallTracerResult::CallTrace(ResultDebugCall { + result: call, + })) } - }) - .collect(); + CallTracerOption::FlattCallTrace(mut call) => flat_calls.append(&mut call), + } + } + if calls.is_empty() && !flat_calls.is_empty() { + calls.push(CallTracerResult::FlattCallTrace(flat_calls)) + } - Ok(call_trace) + Ok(calls) } pub async fn debug_trace_transaction_impl( &self, tx_hash: H256, options: Option, - ) -> Result, Web3Error> { + ) -> Result, Web3Error> { let mut connection = self.state.acquire_connection().await?; let call_trace = connection .transactions_dal() @@ -239,7 +240,7 @@ impl DebugNamespace { mut request: CallRequest, block_id: Option, options: Option, - ) -> Result { + ) -> Result { let block_id = block_id.unwrap_or(BlockId::Number(BlockNumber::Pending)); self.current_method().set_block_id(block_id); diff --git a/core/node/api_server/src/web3/tests/debug.rs b/core/node/api_server/src/web3/tests/debug.rs index 48450cfc99e8..b1d6a1aed0eb 100644 --- a/core/node/api_server/src/web3/tests/debug.rs +++ b/core/node/api_server/src/web3/tests/debug.rs @@ -2,7 +2,10 @@ use zksync_multivm::interface::{Call, TransactionExecutionResult}; use zksync_types::{ - api::{CallTracerConfig, CallTracerOption, CallTracerResult, SupportedTracers, TracerConfig}, + api::{ + CallTracerConfig, CallTracerOption, CallTracerResult, ResultDebugCall, SupportedTracers, + TracerConfig, + }, BOOTLOADER_ADDRESS, }; use zksync_web3_decl::{ @@ -65,7 +68,7 @@ impl HttpTest for TraceBlockTest { assert_eq!(block_traces.len(), tx_results.len()); // equals to the number of transactions in the block for (trace, tx_result) in block_traces.iter().zip(&tx_results) { - let CallTracerOption::CallTrace(result) = trace else { + let CallTracerResult::CallTrace(ResultDebugCall { result }) = trace else { unreachable!() }; assert_eq!(result.from, Address::zero()); @@ -159,9 +162,10 @@ impl HttpTest for TraceBlockFlatTest { .map(|&i| block_traces[i].clone()); for (top_level_trace, tx_result) in top_level_traces.zip(&tx_results) { - let CallTracerOption::FlattCallTrace(top_level_trace) = top_level_trace else { + let CallTracerResult::FlattCallTrace(top_level_trace) = top_level_trace else { unreachable!() }; + let top_level_trace = top_level_trace.first().unwrap(); assert_eq!(top_level_trace.action.from, Address::zero()); assert_eq!(top_level_trace.action.to, BOOTLOADER_ADDRESS); assert_eq!( @@ -227,7 +231,7 @@ impl HttpTest for TraceTransactionTest { .map(|call| DebugNamespace::map_default_call(call.clone(), false)) .collect(); - let CallTracerResult::CallTrace(result) = client + let CallTracerOption::CallTrace(result) = client .trace_transaction(tx_results[0].hash, None) .await? .context("no transaction traces")? diff --git a/core/node/api_server/src/web3/tests/vm.rs b/core/node/api_server/src/web3/tests/vm.rs index 0fdef207e6ca..f8571b62fbcc 100644 --- a/core/node/api_server/src/web3/tests/vm.rs +++ b/core/node/api_server/src/web3/tests/vm.rs @@ -7,7 +7,7 @@ use zksync_multivm::interface::{ ExecutionResult, VmExecutionLogs, VmExecutionResultAndLogs, VmRevertReason, }; use zksync_types::{ - api::{ApiStorageLog, CallTracerResult}, + api::{ApiStorageLog, CallTracerOption}, get_intrinsic_constants, transaction_request::CallRequest, K256PrivateKey, L2ChainId, PackedEthSignature, StorageLogKind, StorageLogWithPreviousValue, @@ -430,14 +430,14 @@ impl HttpTest for TraceCallTest { drop(connection); let call_request = CallTest::call_request(b"pending"); - let CallTracerResult::CallTrace(call_result) = + let CallTracerOption::CallTrace(call_result) = client.trace_call(call_request.clone(), None, None).await? else { unreachable!() }; Self::assert_debug_call(&call_request, &call_result); let pending_block_number = api::BlockId::Number(api::BlockNumber::Pending); - let CallTracerResult::CallTrace(call_result) = client + let CallTracerOption::CallTrace(call_result) = client .trace_call(call_request.clone(), Some(pending_block_number), None) .await? else { @@ -448,7 +448,7 @@ impl HttpTest for TraceCallTest { let latest_block_numbers = [api::BlockNumber::Latest, 1.into()]; let call_request = CallTest::call_request(b"latest"); for number in latest_block_numbers { - let CallTracerResult::CallTrace(call_result) = client + let CallTracerOption::CallTrace(call_result) = client .trace_call( call_request.clone(), Some(api::BlockId::Number(number)), @@ -505,14 +505,14 @@ impl HttpTest for TraceCallTestAfterSnapshotRecovery { _pool: &ConnectionPool, ) -> anyhow::Result<()> { let call_request = CallTest::call_request(b"pending"); - let CallTracerResult::CallTrace(call_result) = + let CallTracerOption::CallTrace(call_result) = client.trace_call(call_request.clone(), None, None).await? else { unreachable!() }; TraceCallTest::assert_debug_call(&call_request, &call_result); let pending_block_number = api::BlockId::Number(api::BlockNumber::Pending); - let CallTracerResult::CallTrace(call_result) = client + let CallTracerOption::CallTrace(call_result) = client .trace_call(call_request.clone(), Some(pending_block_number), None) .await? else { @@ -535,7 +535,7 @@ impl HttpTest for TraceCallTestAfterSnapshotRecovery { let first_l2_block_numbers = [api::BlockNumber::Latest, first_local_l2_block.0.into()]; for number in first_l2_block_numbers { let number = api::BlockId::Number(number); - let CallTracerResult::CallTrace(call_result) = client + let CallTracerOption::CallTrace(call_result) = client .trace_call(call_request.clone(), Some(number), None) .await? else { diff --git a/core/tests/ts-integration/tests/api/debug.test.ts b/core/tests/ts-integration/tests/api/debug.test.ts index 054aa57cf64e..60c51b1a3a94 100644 --- a/core/tests/ts-integration/tests/api/debug.test.ts +++ b/core/tests/ts-integration/tests/api/debug.test.ts @@ -75,7 +75,7 @@ describe('Debug methods', () => { input: expect.any(String), output: '0x', to: BOOTLOADER_FORMAL_ADDRESS, - type: 'Call', + type: 'call', value: expect.any(String), calls: expect.any(Array) // We intentionally skip `error` and `revertReason` fields: the block may contain failing txs @@ -99,7 +99,7 @@ describe('Debug methods', () => { output: '0x', revertReason: null, to: BOOTLOADER_FORMAL_ADDRESS, - type: 'Call', + type: 'call', value: '0x0', calls: expect.any(Array) };