Skip to content

Commit e588acf

Browse files
authored
pallet-revive: add DebugSetting for bypassing eip-3607 (#10387)
Only works for contract accounts, not precompiles. This is needed so that test nodes like anvil can send transactions from contract accounts, a widely-used feature in tests Needed for paritytech/foundry-polkadot#423
1 parent 8a034ca commit e588acf

File tree

5 files changed

+101
-7
lines changed

5 files changed

+101
-7
lines changed

prdoc/pr_10387.prdoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
title: "pallet-revive: add DebugSetting for bypassing eip-3607 for contracts and precompiles"
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Adds a new DebugSetting option which, if enabled, allows transactions coming from contract accounts or precompiles.
6+
This is needed so that test nodes like anvil can send transactions from
7+
contract or precompile accounts, a widely-used feature in tests.
8+
9+
crates:
10+
- name: pallet-revive
11+
bump: major

substrate/frame/revive/src/debug.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,27 @@ use sp_runtime::RuntimeDebug;
3838
pub struct DebugSettings {
3939
/// Whether to allow unlimited contract size.
4040
allow_unlimited_contract_size: bool,
41+
/// Whether to allow bypassing EIP-3607 (allowing transactions coming from contract or
42+
/// precompile accounts).
43+
bypass_eip_3607: bool,
4144
}
4245

4346
impl DebugSettings {
44-
pub fn new(allow_unlimited_contract_size: bool) -> Self {
45-
Self { allow_unlimited_contract_size }
47+
pub fn new(allow_unlimited_contract_size: bool, bypass_eip_3607: bool) -> Self {
48+
Self { allow_unlimited_contract_size, bypass_eip_3607 }
4649
}
4750

4851
/// Returns true if unlimited contract size is allowed.
4952
pub fn is_unlimited_contract_size_allowed<T: Config>() -> bool {
5053
T::DebugEnabled::get() && DebugSettingsOf::<T>::get().allow_unlimited_contract_size
5154
}
5255

56+
/// Returns true if transactions coming from contract or precompile accounts are allowed
57+
/// (bypassing EIP-3607)
58+
pub fn bypass_eip_3607<T: Config>() -> bool {
59+
T::DebugEnabled::get() && DebugSettingsOf::<T>::get().bypass_eip_3607
60+
}
61+
5362
/// Write the debug settings to storage.
5463
pub fn write_to_storage<T: Config>(&self) {
5564
DebugSettingsOf::<T>::put(self);

substrate/frame/revive/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,6 +2368,9 @@ impl<T: Config> Pallet<T> {
23682368
///
23692369
/// This enforces EIP-3607.
23702370
fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
2371+
if DebugSettings::bypass_eip_3607::<T>() {
2372+
return Ok(())
2373+
}
23712374
let Some(address) = origin
23722375
.as_system_ref()
23732376
.and_then(|o| o.as_signed())

substrate/frame/revive/src/tests/pvm.rs

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ use crate::{
4141
tracing::trace,
4242
weights::WeightInfo,
4343
AccountInfo, AccountInfoOf, BalanceWithDust, Code, Combinator, Config, ContractInfo,
44-
DeletionQueueCounter, Error, ExecConfig, HoldReason, Origin, Pallet, PristineCode,
45-
StorageDeposit, H160,
44+
DebugSettings, DeletionQueueCounter, Error, ExecConfig, HoldReason, Origin, Pallet,
45+
PristineCode, StorageDeposit, H160,
4646
};
4747
use assert_matches::assert_matches;
4848
use codec::Encode;
@@ -4973,7 +4973,7 @@ fn eip3607_reject_tx_from_contract_or_precompile() {
49734973
assert_err!(result, DispatchError::BadOrigin);
49744974

49754975
let result = builder::eth_call(BOB_ADDR)
4976-
.origin(RuntimeOrigin::signed(origin.clone()))
4976+
.origin(Origin::EthTransaction(origin.clone()).into())
49774977
.build();
49784978
assert_err!(result, DispatchError::BadOrigin);
49794979

@@ -4983,7 +4983,7 @@ fn eip3607_reject_tx_from_contract_or_precompile() {
49834983
assert_err!(result, DispatchError::BadOrigin);
49844984

49854985
let result = builder::eth_instantiate_with_code(Default::default())
4986-
.origin(RuntimeOrigin::signed(origin.clone()))
4986+
.origin(Origin::EthTransaction(origin.clone()).into())
49874987
.build();
49884988
assert_err!(result, DispatchError::BadOrigin);
49894989

@@ -5011,6 +5011,77 @@ fn eip3607_reject_tx_from_contract_or_precompile() {
50115011
});
50125012
}
50135013

5014+
#[test]
5015+
fn eip3607_allow_tx_from_contract_or_precompile_if_debug_setting_configured() {
5016+
let (binary, code_hash) = compile_module("dummy").unwrap();
5017+
5018+
let genesis_config = GenesisConfig::<Test> {
5019+
debug_settings: Some(DebugSettings::new(false, true)),
5020+
..Default::default()
5021+
};
5022+
5023+
ExtBuilder::default()
5024+
.genesis_config(Some(genesis_config))
5025+
.existential_deposit(200)
5026+
.build()
5027+
.execute_with(|| {
5028+
DebugFlag::set(true);
5029+
5030+
let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000);
5031+
5032+
// the origins from which we try to call a dispatchable
5033+
let Contract { addr: contract_addr, .. } =
5034+
builder::bare_instantiate(Code::Upload(binary.clone())).build_and_unwrap_contract();
5035+
5036+
assert!(<AccountInfo<Test>>::is_contract(&contract_addr));
5037+
5038+
let blake2_addr = H160::from_low_u64_be(9);
5039+
let system_addr = H160::from_low_u64_be(0x900);
5040+
let addresses = [contract_addr, blake2_addr, system_addr];
5041+
5042+
for address in addresses {
5043+
let origin = <Test as Config>::AddressMapper::to_fallback_account_id(&address);
5044+
5045+
let _ = <Test as Config>::Currency::set_balance(&origin, 10_000_000_000_000);
5046+
5047+
let result =
5048+
builder::call(BOB_ADDR).origin(RuntimeOrigin::signed(origin.clone())).build();
5049+
assert_ok!(result);
5050+
5051+
let result = builder::eth_call(BOB_ADDR)
5052+
.origin(Origin::EthTransaction(origin.clone()).into())
5053+
.build();
5054+
assert_ok!(result);
5055+
5056+
let result = builder::instantiate(code_hash)
5057+
.origin(RuntimeOrigin::signed(origin.clone()))
5058+
.build();
5059+
assert_ok!(result);
5060+
5061+
let result = builder::eth_instantiate_with_code(binary.clone())
5062+
.origin(Origin::EthTransaction(origin.clone()).into())
5063+
.build();
5064+
assert_ok!(result);
5065+
5066+
let result = <Pallet<Test>>::dispatch_as_fallback_account(
5067+
RuntimeOrigin::signed(origin.clone()),
5068+
Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_all {
5069+
dest: EVE,
5070+
keep_alive: false,
5071+
})),
5072+
);
5073+
assert_ok!(result);
5074+
5075+
let result = <Pallet<Test>>::upload_code(
5076+
RuntimeOrigin::signed(origin.clone()),
5077+
binary.clone(),
5078+
<BalanceOf<Test>>::MAX,
5079+
);
5080+
assert_ok!(result);
5081+
}
5082+
});
5083+
}
5084+
50145085
#[test]
50155086
fn get_set_storage_key_works() {
50165087
let (code, _code_hash) = compile_module("dummy").unwrap();

substrate/frame/revive/src/tests/sol.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ fn eth_contract_too_large() {
180180

181181
// Initialize genesis config with allow_unlimited_contract_size
182182
let genesis_config = GenesisConfig::<Test> {
183-
debug_settings: Some(DebugSettings::new(allow_unlimited_contract_size)),
183+
debug_settings: Some(DebugSettings::new(allow_unlimited_contract_size, false)),
184184
..Default::default()
185185
};
186186

0 commit comments

Comments
 (0)