Skip to content

Commit

Permalink
Merge branch 'master' into lexnv/release-0.9.1
Browse files Browse the repository at this point in the history
  • Loading branch information
lexnv authored Feb 20, 2025
2 parents 2f5064d + 9e75647 commit d5bc5d0
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 24 deletions.
14 changes: 9 additions & 5 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2372,11 +2372,15 @@ impl_runtime_apis! {
{
use pallet_revive::tracing::trace;
let mut tracer = config.build(Revive::evm_gas_from_weight);
trace(&mut tracer, || {
Self::eth_transact(tx)
})?;

Ok(tracer.collect_traces().pop().expect("eth_transact succeeded, trace must exist, qed"))
let result = trace(&mut tracer, || Self::eth_transact(tx));

if let Some(trace) = tracer.collect_traces().pop() {
Ok(trace)
} else if let Err(err) = result {
Err(err)
} else {
Ok(Default::default())
}
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions prdoc/pr_7614.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
title: '[pallet-revive] tracing improvements'
doc:
- audience: Runtime Dev
description: |-
Various pallet-revive improvements

- add check for precompiles addresses,
So we can easily identified which one are being called and not supported yet

- fixes debug_call for revert call
If a call revert we still want to get the traces for that call, that matches geth behaviors, diff tests will be added to the test suite for this

- fixes traces for staticcall
The call type was not always being reported properly.
crates:
- name: asset-hub-westend-runtime
bump: minor
- name: pallet-revive-eth-rpc
bump: minor
- name: pallet-revive
bump: minor
14 changes: 9 additions & 5 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3745,11 +3745,15 @@ impl_runtime_apis! {
{
use pallet_revive::tracing::trace;
let mut tracer = config.build(Revive::evm_gas_from_weight);
trace(&mut tracer, || {
Self::eth_transact(tx)
})?;

Ok(tracer.collect_traces().pop().expect("eth_transact succeeded, trace must exist, qed"))
let result = trace(&mut tracer, || Self::eth_transact(tx));

if let Some(trace) = tracer.collect_traces().pop() {
Ok(trace)
} else if let Err(err) = result {
Err(err)
} else {
Ok(Default::default())
}
}
}

Expand Down
Binary file modified substrate/frame/revive/rpc/revive_chain.metadata
Binary file not shown.
3 changes: 2 additions & 1 deletion substrate/frame/revive/src/evm/api/debug_rpc_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ pub struct CallTrace<Gas = U256> {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub logs: Vec<CallLog>,
/// Amount of value transferred.
pub value: U256,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<U256>,
/// Type of call.
#[serde(rename = "type")]
pub call_type: CallType,
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/evm/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl<Gas: Default, GasMapper: Fn(Weight) -> Gas> Tracer for CallTracer<Gas, GasM
self.traces.push(CallTrace {
from,
to,
value,
value: if is_read_only { None } else { Some(value) },
call_type,
input: input.to_vec().into(),
gas: (self.gas_mapper)(gas_left),
Expand Down
40 changes: 31 additions & 9 deletions substrate/frame/revive/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,13 @@ where
}
}

/// Determine if the given address is a precompile.
/// For now, we consider that all addresses between 0x1 and 0xff are reserved for precompiles.
fn is_precompile(address: &H160) -> bool {
let bytes = address.as_bytes();
bytes.starts_with(&[0u8; 19]) && bytes[19] != 0
}

impl<'a, T, E> Ext for Stack<'a, T, E>
where
T: Config,
Expand Down Expand Up @@ -1403,6 +1410,11 @@ where
*self.last_frame_output_mut() = Default::default();

let try_call = || {
if is_precompile(dest_addr) {
log::debug!(target: crate::LOG_TARGET, "Unsupported precompile address {dest_addr:?}");
return Err(Error::<T>::UnsupportedPrecompileAddress.into());
}

let dest = T::AddressMapper::to_account_id(dest_addr);
if !self.allows_reentry(&dest) {
return Err(<Error<T>>::ReentranceDenied.into());
Expand All @@ -1420,28 +1432,38 @@ where
CachedContract::Cached(contract) => Some(contract.clone()),
_ => None,
});

// Enable read-only access if requested; cannot disable it if already set.
let is_read_only = read_only || self.is_read_only();

if let Some(executable) = self.push_frame(
FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
value,
gas_limit,
deposit_limit.saturated_into::<BalanceOf<T>>(),
// Enable read-only access if requested; cannot disable it if already set.
read_only || self.is_read_only(),
is_read_only,
)? {
self.run(executable, input_data)
} else {
let result = Self::transfer_from_origin(
&self.origin,
&Origin::from_account_id(self.account_id().clone()),
&dest,
value,
);
let result = if is_read_only && value.is_zero() {
Ok(Default::default())
} else if is_read_only {
Err(Error::<T>::StateChangeDenied.into())
} else {
Self::transfer_from_origin(
&self.origin,
&Origin::from_account_id(self.account_id().clone()),
&dest,
value,
)
};

if_tracing(|t| {
t.enter_child_span(
T::AddressMapper::to_address(self.account_id()),
T::AddressMapper::to_address(&dest),
false,
false,
is_read_only,
value,
&input_data,
Weight::zero(),
Expand Down
2 changes: 2 additions & 0 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ pub mod pallet {
InvalidGenericTransaction,
/// The refcount of a code either over or underflowed.
RefcountOverOrUnderflow,
/// Unsupported precompile address
UnsupportedPrecompileAddress,
}

/// A reason for the pallet contracts placing a hold on funds.
Expand Down
5 changes: 4 additions & 1 deletion substrate/frame/revive/src/test_utils/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ builder!(

/// Build the instantiate call and unwrap the account id.
pub fn build_and_unwrap_contract(self) -> Contract<T> {
let addr = self.build().result.unwrap().addr;
let result = self.build().result.unwrap();
assert!(!result.result.did_revert(), "instantiation did revert");

let addr = result.addr;
let account_id = T::AddressMapper::to_account_id(&addr);
Contract{ account_id, addr }
}
Expand Down
49 changes: 47 additions & 2 deletions substrate/frame/revive/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4441,7 +4441,7 @@ fn tracing_works_for_transfers() {
vec![CallTrace {
from: ALICE_ADDR,
to: BOB_ADDR,
value: U256::from(10_000_000),
value: Some(U256::from(10_000_000)),
call_type: CallType::Call,
..Default::default()
},]
Expand Down Expand Up @@ -4509,6 +4509,7 @@ fn tracing_works() {
input: (3u32, addr_callee).encode().into(),
call_type: Call,
logs: logs.clone(),
value: Some(U256::from(0)),
calls: vec![
CallTrace {
from: addr,
Expand All @@ -4520,6 +4521,7 @@ fn tracing_works() {
revert_reason: Some("revert: This function always fails".to_string()),
error: Some("execution reverted".to_string()),
call_type: Call,
value: Some(U256::from(0)),
..Default::default()
},
CallTrace {
Expand All @@ -4528,6 +4530,7 @@ fn tracing_works() {
input: (2u32, addr_callee).encode().into(),
call_type: Call,
logs: logs.clone(),
value: Some(U256::from(0)),
calls: vec![
CallTrace {
from: addr,
Expand All @@ -4536,6 +4539,7 @@ fn tracing_works() {
output: Default::default(),
error: Some("ContractTrapped".to_string()),
call_type: Call,
value: Some(U256::from(0)),
..Default::default()
},
CallTrace {
Expand All @@ -4544,25 +4548,28 @@ fn tracing_works() {
input: (1u32, addr_callee).encode().into(),
call_type: Call,
logs: logs.clone(),
value: Some(U256::from(0)),
calls: vec![
CallTrace {
from: addr,
to: addr_callee,
input: 0u32.encode().into(),
output: 0u32.to_le_bytes().to_vec().into(),
call_type: Call,
value: Some(U256::from(0)),
..Default::default()
},
CallTrace {
from: addr,
to: addr,
input: (0u32, addr_callee).encode().into(),
call_type: Call,
value: Some(U256::from(0)),
calls: vec![
CallTrace {
from: addr,
to: BOB_ADDR,
value: U256::from(100),
value: Some(U256::from(100)),
call_type: CallType::Call,
..Default::default()
}
Expand All @@ -4582,3 +4589,41 @@ fn tracing_works() {
}
});
}

#[test]
fn unknown_precompiles_revert() {
let (code, _code_hash) = compile_module("read_only_call").unwrap();

ExtBuilder::default().build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 100_000_000_000);
let Contract { addr, .. } =
builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract();

let cases: Vec<(H160, Box<dyn FnOnce(_)>)> = vec![
(
H160::from_low_u64_be(0x1),
Box::new(|result| {
assert_err!(result, <Error<Test>>::UnsupportedPrecompileAddress);
}),
),
(
H160::from_low_u64_be(0xff),
Box::new(|result| {
assert_err!(result, <Error<Test>>::UnsupportedPrecompileAddress);
}),
),
(
H160::from_low_u64_be(0x1ff),
Box::new(|result| {
assert_ok!(result);
}),
),
];

for (callee_addr, assert_result) in cases {
let result =
builder::bare_call(addr).data((callee_addr, [0u8; 0]).encode()).build().result;
assert_result(result);
}
});
}

0 comments on commit d5bc5d0

Please sign in to comment.