diff --git a/runtime/common/src/apis.rs b/runtime/common/src/apis.rs index c2f237ba4f..368c97f53f 100644 --- a/runtime/common/src/apis.rs +++ b/runtime/common/src/apis.rs @@ -17,6 +17,31 @@ #[macro_export] macro_rules! impl_runtime_apis_plus_common { {$($custom:tt)*} => { + + #[cfg(feature = "evm-tracing")] + // Helper function to replay the "on_idle" hook for all pallets, we need this for + // evm-tracing because some ethereum-xcm transactions might be executed at on_idle. + // + // We need to make sure that we replay on_idle exactly the same way as the + // original block execution, but unfortunatly frame executive diosn't provide a function + // to replay only on_idle, so we need to copy here some code inside frame executive. + fn replay_on_idle() { + use frame_system::pallet_prelude::BlockNumberFor; + + let weight = >::block_weight(); + let max_weight = < + ::BlockWeights as + frame_support::traits::Get<_> + >::get().max_block; + let remaining_weight = max_weight.saturating_sub(weight.total()); + if remaining_weight.all_gt(Weight::zero()) { + let _ = >>::on_idle( + >::block_number(), + remaining_weight, + ); + } + } + impl_runtime_apis! { $($custom)* @@ -111,6 +136,7 @@ macro_rules! impl_runtime_apis_plus_common { EthereumXcmTracingStatus }; use frame_support::storage::unhashed; + use frame_system::pallet_prelude::BlockNumberFor; // Tell the CallDispatcher we are tracing a specific Transaction. unhashed::put::( @@ -138,9 +164,26 @@ macro_rules! impl_runtime_apis_plus_common { return Ok(()); } } - Err(sp_runtime::DispatchError::Other( - "Failed to find Ethereum transaction among the extrinsics.", - )) + + if let Some(EthereumXcmTracingStatus::Transaction(_)) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // If the transaction was not found, it might be + // an eth-xcm transaction that was executed at on_idle + replay_on_idle(); + } + + if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get( + ETHEREUM_XCM_TRACING_STORAGE_KEY + ) { + // The transaction was found + Ok(()) + } else { + // The transaction was not-found + Err(sp_runtime::DispatchError::Other( + "Failed to find Ethereum transaction among the extrinsics.", + )) + } } #[cfg(not(feature = "evm-tracing"))] Err(sp_runtime::DispatchError::Other( @@ -158,6 +201,7 @@ macro_rules! impl_runtime_apis_plus_common { #[cfg(feature = "evm-tracing")] { use moonbeam_evm_tracer::tracer::EvmTracer; + use frame_system::pallet_prelude::BlockNumberFor; use xcm_primitives::EthereumXcmTracingStatus; // Tell the CallDispatcher we are tracing a full Block. @@ -187,6 +231,10 @@ macro_rules! impl_runtime_apis_plus_common { }; } + // Replay on_idle + // Some XCM messages with eth-xcm transaction might be executed at on_idle + replay_on_idle(); + Ok(()) } #[cfg(not(feature = "evm-tracing"))] diff --git a/runtime/moonbase/tests/evm_tracing.rs b/runtime/moonbase/tests/evm_tracing.rs index 85fffcbf9e..89106ec6c7 100644 --- a/runtime/moonbase/tests/evm_tracing.rs +++ b/runtime/moonbase/tests/evm_tracing.rs @@ -84,6 +84,7 @@ mod tests { let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); let eth_tx = ethereum_transaction(VALID_ETH_TX); let eth_extrinsic_hash = eth_tx.hash(); + assert!(Runtime::trace_block( vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], vec![eth_extrinsic_hash, eth_extrinsic_hash] diff --git a/runtime/moonbeam/tests/evm_tracing.rs b/runtime/moonbeam/tests/evm_tracing.rs index 5d241a8850..f7fe777829 100644 --- a/runtime/moonbeam/tests/evm_tracing.rs +++ b/runtime/moonbeam/tests/evm_tracing.rs @@ -84,6 +84,7 @@ mod tests { let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); let eth_tx = ethereum_transaction(VALID_ETH_TX); let eth_extrinsic_hash = eth_tx.hash(); + assert!(Runtime::trace_block( vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], vec![eth_extrinsic_hash, eth_extrinsic_hash] diff --git a/runtime/moonriver/tests/evm_tracing.rs b/runtime/moonriver/tests/evm_tracing.rs index c8db27d0ff..9acf4de3b8 100644 --- a/runtime/moonriver/tests/evm_tracing.rs +++ b/runtime/moonriver/tests/evm_tracing.rs @@ -84,6 +84,7 @@ mod tests { let eth_uxt = unchecked_eth_tx(VALID_ETH_TX); let eth_tx = ethereum_transaction(VALID_ETH_TX); let eth_extrinsic_hash = eth_tx.hash(); + assert!(Runtime::trace_block( vec![non_eth_uxt.clone(), eth_uxt.clone(), non_eth_uxt, eth_uxt], vec![eth_extrinsic_hash, eth_extrinsic_hash]