Skip to content

Commit

Permalink
[pallet-revive] Add tracing support (1/3) (#7166)
Browse files Browse the repository at this point in the history
Add foundation for supporting call traces in pallet_revive

Follow up:
- PR #7167 Add changes to eth-rpc to introduce debug endpoint that will
use pallet-revive tracing features
- PR #6727 Add new RPC to the client and implement tracing runtime API
that can capture traces on previous blocks

---------

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
  • Loading branch information
pgherveou and athei authored Jan 17, 2025
1 parent f90a785 commit 7702fdd
Show file tree
Hide file tree
Showing 22 changed files with 912 additions and 491 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,6 @@ impl pallet_revive::Config for Runtime {
type InstantiateOrigin = EnsureSigned<Self::AccountId>;
type RuntimeHoldReason = RuntimeHoldReason;
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
type Debug = ();
type Xcm = pallet_xcm::Pallet<Self>;
type ChainId = ConstU64<420_420_421>;
type NativeToEthRatio = ConstU32<1_000_000>; // 10^(18 - 12) Eth is 10^18, Native is 10^12.
Expand Down
1 change: 0 additions & 1 deletion substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,6 @@ impl pallet_revive::Config for Runtime {
type InstantiateOrigin = EnsureSigned<Self::AccountId>;
type RuntimeHoldReason = RuntimeHoldReason;
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
type Debug = ();
type Xcm = ();
type ChainId = ConstU64<420_420_420>;
type NativeToEthRatio = ConstU32<1_000_000>; // 10^(18 - 12) Eth is 10^18, Native is 10^12.
Expand Down
2 changes: 2 additions & 0 deletions substrate/frame/revive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { features = ["derive", "max-encoded-len"], workspace = true }
derive_more = { workspace = true }
environmental = { workspace = true }
ethabi = { workspace = true }
ethereum-types = { workspace = true, features = ["codec", "rlp", "serialize"] }
hex = { workspace = true }
impl-trait-for-tuples = { workspace = true }
Expand Down Expand Up @@ -75,6 +76,7 @@ default = ["std"]
std = [
"codec/std",
"environmental/std",
"ethabi/std",
"ethereum-types/std",
"frame-benchmarking?/std",
"frame-support/std",
Expand Down
1 change: 1 addition & 0 deletions substrate/frame/revive/fixtures/build/_Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ edition = "2021"
[dependencies]
uapi = { package = 'pallet-revive-uapi', path = "", features = ["unstable-hostfn"], default-features = false }
common = { package = 'pallet-revive-fixtures-common', path = "" }
hex-literal = { version = "0.4.1", default-features = false }
polkavm-derive = { version = "0.19.0" }

[profile.release]
Expand Down
75 changes: 75 additions & 0 deletions substrate/frame/revive/fixtures/contracts/tracing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This fixture calls itself as many times as passed as argument.
#![no_std]
#![no_main]

use common::input;
use uapi::{HostFn, HostFnImpl as api};

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn deploy() {}

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn call() {
input!(calls_left: u32, callee_addr: &[u8; 20],);
if calls_left == 0 {
return
}

let next_input = (calls_left - 1).to_le_bytes();
api::deposit_event(&[], b"before");

// Call the callee, ignore revert.
let _ = api::call(
uapi::CallFlags::empty(),
callee_addr,
u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all.
u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all.
&[u8::MAX; 32], // No deposit limit.
&[0u8; 32], // Value transferred to the contract.
&next_input,
None,
);

api::deposit_event(&[], b"after");

// own address
let mut addr = [0u8; 20];
api::address(&mut addr);
let mut input = [0u8; 24];

input[..4].copy_from_slice(&next_input);
input[4..24].copy_from_slice(&callee_addr[..20]);

// recurse
api::call(
uapi::CallFlags::ALLOW_REENTRY,
&addr,
u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all.
u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all.
&[u8::MAX; 32], // No deposit limit.
&[0u8; 32], // Value transferred to the contract.
&input,
None,
)
.unwrap();
}
45 changes: 45 additions & 0 deletions substrate/frame/revive/fixtures/contracts/tracing_callee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_std]
#![no_main]

use common::input;
use uapi::{HostFn, HostFnImpl as api};

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn deploy() {}

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn call() {
input!(id: u32, );

match id {
// Revert with message "This function always fails"
2 => {
let data = hex_literal::hex!(
"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001a546869732066756e6374696f6e20616c77617973206661696c73000000000000"
);
api::return_value(uapi::ReturnFlags::REVERT, &data)
},
1 => {
panic!("booum");
},
_ => api::return_value(uapi::ReturnFlags::empty(), &id.to_le_bytes()),
};
}
46 changes: 3 additions & 43 deletions substrate/frame/revive/rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use crate::{
use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObjectOwned};
use pallet_revive::{
evm::{
Block, BlockNumberOrTag, BlockNumberOrTagOrHash, GenericTransaction, ReceiptInfo,
SyncingProgress, SyncingStatus, TransactionSigned, H160, H256, U256,
extract_revert_message, Block, BlockNumberOrTag, BlockNumberOrTagOrHash,
GenericTransaction, ReceiptInfo, SyncingProgress, SyncingStatus, TransactionSigned, H160,
H256, U256,
},
EthTransactError, EthTransactInfo,
};
Expand Down Expand Up @@ -83,47 +84,6 @@ fn unwrap_call_err(err: &subxt::error::RpcError) -> Option<ErrorObjectOwned> {
}
}

/// Extract the revert message from a revert("msg") solidity statement.
fn extract_revert_message(exec_data: &[u8]) -> Option<String> {
let error_selector = exec_data.get(0..4)?;

match error_selector {
// assert(false)
[0x4E, 0x48, 0x7B, 0x71] => {
let panic_code: u32 = U256::from_big_endian(exec_data.get(4..36)?).try_into().ok()?;

// See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
let msg = match panic_code {
0x00 => "generic panic",
0x01 => "assert(false)",
0x11 => "arithmetic underflow or overflow",
0x12 => "division or modulo by zero",
0x21 => "enum overflow",
0x22 => "invalid encoded storage byte array accessed",
0x31 => "out-of-bounds array access; popping on an empty array",
0x32 => "out-of-bounds access of an array or bytesN",
0x41 => "out of memory",
0x51 => "uninitialized function",
code => return Some(format!("execution reverted: unknown panic code: {code:#x}")),
};

Some(format!("execution reverted: {msg}"))
},
// revert(string)
[0x08, 0xC3, 0x79, 0xA0] => {
let decoded = ethabi::decode(&[ethabi::ParamType::String], &exec_data[4..]).ok()?;
if let Some(ethabi::Token::String(msg)) = decoded.first() {
return Some(format!("execution reverted: {msg}"))
}
Some("execution reverted".to_string())
},
_ => {
log::debug!(target: LOG_TARGET, "Unknown revert function selector: {error_selector:?}");
Some("execution reverted".to_string())
},
}
}

/// The error type for the client.
#[derive(Error, Debug)]
pub enum ClientError {
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ mod benchmarks {
let mut setup = CallSetup::<T>::default();
let input = setup.data();
let (mut ext, _) = setup.ext();
ext.override_export(crate::debug::ExportedFunction::Constructor);
ext.override_export(crate::exec::ExportedFunction::Constructor);

let mut runtime = crate::wasm::Runtime::<_, [u8]>::new(&mut ext, input);

Expand Down
109 changes: 0 additions & 109 deletions substrate/frame/revive/src/debug.rs

This file was deleted.

Loading

0 comments on commit 7702fdd

Please sign in to comment.