Skip to content

Commit 067c829

Browse files
committed
Add contract creation filters to EVM test runtime
1 parent 388e54d commit 067c829

File tree

7 files changed

+135
-23
lines changed

7 files changed

+135
-23
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/sp-domains-fraud-proof/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ domain-block-builder = { version = "0.1.0", path = "../../domains/client/block-b
4545
domain-block-preprocessor = { version = "0.1.0", path = "../../domains/client/block-preprocessor" }
4646
domain-test-service = { version = "0.1.0", path = "../../domains/test/service" }
4747
ethereum = "0.15.0"
48+
evm-domain-test-runtime = { version = "0.1.0", path = "../../domains/test/runtime/evm" }
4849
fp-rpc = { version = "3.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968" }
4950
fp-self-contained = { version = "1.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968" }
5051
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }

crates/sp-domains-fraud-proof/src/tests.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use domain_test_service::evm_domain_test_runtime::{
44
Runtime as TestRuntime, RuntimeCall, Signature, UncheckedExtrinsic as EvmUncheckedExtrinsic,
55
};
66
use domain_test_service::EcdsaKeyring::{Alice, Charlie};
7+
use domain_test_service::EvmDomainNode;
78
use domain_test_service::Sr25519Keyring::Ferdie;
8-
use domain_test_service::{construct_extrinsic_raw_payload, EvmDomainNode};
99
use ethereum::TransactionV2 as EthereumTransaction;
10+
use evm_domain_test_runtime::construct_extrinsic_raw_payload;
1011
use fp_rpc::EthereumRuntimeRPCApi;
1112
use rand::distributions::{Distribution, Uniform};
1213
use sc_client_api::{HeaderBackend, StorageProof};
@@ -127,8 +128,20 @@ async fn benchmark_bundle_with_evm_tx(
127128
value: other_accounts_balance,
128129
}
129130
.into();
130-
let (raw_payload, extra) =
131-
construct_extrinsic_raw_payload(&alice.client, function.clone(), false, 0, 1);
131+
132+
let current_block_hash = alice.client.as_ref().info().best_hash;
133+
let current_block = alice.client.as_ref().info().best_number;
134+
let genesis_block_hash = alice.client.as_ref().hash(0).unwrap().unwrap();
135+
136+
let (raw_payload, extra) = construct_extrinsic_raw_payload(
137+
current_block_hash,
138+
current_block,
139+
genesis_block_hash,
140+
function.clone(),
141+
false,
142+
0,
143+
1,
144+
);
132145
let signature = raw_payload.using_encoded(|e| {
133146
let msg = keccak_256(e);
134147
ecdsa_key.sign_prehashed(&msg)

domains/pallets/evm-tracker/src/create_contract.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,21 @@ where
126126
}
127127

128128
/// Reject contract creation, unless the account is in the current evm contract allow list.
129-
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
129+
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
130130
pub struct CheckContractCreation<Runtime>(PhantomData<Runtime>);
131131

132+
impl<Runtime> CheckContractCreation<Runtime> {
133+
pub fn new() -> Self {
134+
Self(PhantomData)
135+
}
136+
}
137+
138+
impl<Runtime> Default for CheckContractCreation<Runtime> {
139+
fn default() -> Self {
140+
Self::new()
141+
}
142+
}
143+
132144
// Unsigned calls can't create contracts. Only pallet-evm and pallet-ethereum can create contracts.
133145
// For pallet-evm all contracts are signed extrinsics, for pallet-ethereum there is only one
134146
// extrinsic that is self-contained.

domains/test/runtime/evm/src/lib.rs

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use core::mem;
1919
pub use domain_runtime_primitives::opaque::Header;
2020
use domain_runtime_primitives::{
2121
block_weights, maximum_block_length, maximum_domain_block_weight, EthereumAccountId,
22-
ERR_BALANCE_OVERFLOW, ERR_NONCE_OVERFLOW, EXISTENTIAL_DEPOSIT, SLOT_DURATION,
22+
ERR_BALANCE_OVERFLOW, ERR_CONTRACT_CREATION_NOT_ALLOWED, ERR_NONCE_OVERFLOW,
23+
EXISTENTIAL_DEPOSIT, SLOT_DURATION,
2324
};
2425
pub use domain_runtime_primitives::{
2526
opaque, Balance, BlockNumber, CheckExtrinsicsValidityError, DecodeExtrinsicError,
@@ -38,6 +39,7 @@ use frame_support::weights::constants::{ParityDbWeight, WEIGHT_REF_TIME_PER_SECO
3839
use frame_support::weights::{ConstantMultiplier, Weight};
3940
use frame_support::{construct_runtime, parameter_types};
4041
use frame_system::limits::{BlockLength, BlockWeights};
42+
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
4143
use pallet_block_fees::fees::OnChargeDomainTransaction;
4244
use pallet_ethereum::Call::transact;
4345
use pallet_ethereum::{
@@ -47,6 +49,7 @@ use pallet_evm::{
4749
Account as EVMAccount, EnsureAddressNever, EnsureAddressRoot, FeeCalculator,
4850
IdentityAddressMapping, Runner,
4951
};
52+
use pallet_evm_tracker::create_contract::is_create_contract_allowed;
5053
use pallet_evm_tracker::traits::{MaybeIntoEthCall, MaybeIntoEvmCall};
5154
use pallet_transporter::EndpointHandler;
5255
use sp_api::impl_runtime_apis;
@@ -61,7 +64,7 @@ use sp_messenger::messages::{
6164
use sp_messenger::{ChannelNonce, XdmId};
6265
use sp_messenger_host_functions::{get_storage_key, StorageKeyRequest};
6366
use sp_mmr_primitives::EncodableOpaqueLeaf;
64-
use sp_runtime::generic::Era;
67+
use sp_runtime::generic::{Era, SignedPayload};
6568
use sp_runtime::traits::{
6669
BlakeTwo256, Block as BlockT, Checkable, DispatchInfoOf, Dispatchable, IdentityLookup,
6770
Keccak256, NumberFor, One, PostDispatchInfoOf, SignedExtension, UniqueSaturatedInto,
@@ -72,7 +75,7 @@ use sp_runtime::transaction_validity::{
7275
};
7376
use sp_runtime::{
7477
generic, impl_opaque_keys, ApplyExtrinsicResult, ConsensusEngineId, Digest,
75-
ExtrinsicInclusionMode,
78+
ExtrinsicInclusionMode, SaturatedConversion,
7679
};
7780
pub use sp_runtime::{MultiAddress, Perbill, Permill};
7881
use sp_std::cmp::{max, Ordering};
@@ -84,6 +87,7 @@ use sp_subspace_mmr::domain_mmr_runtime_interface::{
8487
};
8588
use sp_subspace_mmr::{ConsensusChainMmrLeafProof, MmrLeaf};
8689
use sp_version::RuntimeVersion;
90+
use subspace_runtime_primitives::utility::MaybeIntoUtilityCall;
8791
use subspace_runtime_primitives::{
8892
BlockNumber as ConsensusBlockNumber, Hash as ConsensusBlockHash, Moment, SHANNON, SSC,
8993
};
@@ -113,6 +117,7 @@ pub type SignedExtra = (
113117
frame_system::CheckNonce<Runtime>,
114118
domain_check_weight::CheckWeight<Runtime>,
115119
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
120+
pallet_evm_tracker::create_contract::CheckContractCreation<Runtime>,
116121
);
117122

118123
/// Custom signed extra for check_and_pre_dispatch.
@@ -126,6 +131,7 @@ type CustomSignedExtra = (
126131
pallet_evm_tracker::CheckNonce<Runtime>,
127132
domain_check_weight::CheckWeight<Runtime>,
128133
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
134+
pallet_evm_tracker::create_contract::CheckContractCreation<Runtime>,
129135
);
130136

131137
/// Unchecked extrinsic type as expected by this runtime.
@@ -136,6 +142,60 @@ pub type UncheckedExtrinsic =
136142
pub type CheckedExtrinsic =
137143
fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra, H160>;
138144

145+
type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;
146+
147+
pub fn construct_extrinsic_raw_payload(
148+
current_block_hash: H256,
149+
current_block: BlockNumberFor<Runtime>,
150+
genesis_block_hash: H256,
151+
function: RuntimeCallFor<Runtime>,
152+
immortal: bool,
153+
nonce: u32,
154+
tip: BalanceOf<Runtime>,
155+
) -> (
156+
SignedPayload<RuntimeCallFor<Runtime>, SignedExtra>,
157+
SignedExtra,
158+
) {
159+
let current_block = current_block.saturated_into();
160+
let period = u64::from(<Runtime as frame_system::Config>::BlockHashCount::get())
161+
.checked_next_power_of_two()
162+
.map(|c| c / 2)
163+
.unwrap_or(2);
164+
let extra: SignedExtra = (
165+
frame_system::CheckNonZeroSender::<Runtime>::new(),
166+
frame_system::CheckSpecVersion::<Runtime>::new(),
167+
frame_system::CheckTxVersion::<Runtime>::new(),
168+
frame_system::CheckGenesis::<Runtime>::new(),
169+
frame_system::CheckMortality::<Runtime>::from(if immortal {
170+
generic::Era::Immortal
171+
} else {
172+
generic::Era::mortal(period, current_block)
173+
}),
174+
frame_system::CheckNonce::<Runtime>::from(nonce),
175+
domain_check_weight::CheckWeight::<Runtime>::new(),
176+
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
177+
pallet_evm_tracker::create_contract::CheckContractCreation::<Runtime>::new(),
178+
);
179+
(
180+
generic::SignedPayload::<RuntimeCallFor<Runtime>, SignedExtra>::from_raw(
181+
function,
182+
extra.clone(),
183+
(
184+
(),
185+
1,
186+
0,
187+
genesis_block_hash,
188+
current_block_hash,
189+
(),
190+
(),
191+
(),
192+
(),
193+
),
194+
),
195+
extra,
196+
)
197+
}
198+
139199
/// Executive: handles dispatch to the various modules.
140200
pub type Executive = domain_pallet_executive::Executive<
141201
Runtime,
@@ -167,9 +227,18 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
167227
dispatch_info: &DispatchInfoOf<RuntimeCall>,
168228
len: usize,
169229
) -> Option<TransactionValidity> {
230+
if !is_create_contract_allowed::<Runtime>(self, &(*info).into()) {
231+
return Some(Err(InvalidTransaction::Custom(
232+
ERR_CONTRACT_CREATION_NOT_ALLOWED,
233+
)
234+
.into()));
235+
}
236+
237+
// TODO: move this code into pallet-block-fees, so it can be used from the production and
238+
// test runtimes.
170239
match self {
171240
RuntimeCall::Ethereum(call) => {
172-
// Ensure the caller can pay the consensus chain storage fee
241+
// Ensure the caller can pay for the consensus chain storage fee
173242
let consensus_storage_fee =
174243
BlockFees::consensus_chain_byte_fee().checked_mul(Balance::from(len as u32))?;
175244
let withdraw_res = <InnerEVMCurrencyAdapter as pallet_evm::OnChargeEVMTransaction<
@@ -191,6 +260,15 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
191260
dispatch_info: &DispatchInfoOf<RuntimeCall>,
192261
len: usize,
193262
) -> Option<Result<(), TransactionValidityError>> {
263+
if !is_create_contract_allowed::<Runtime>(self, &(*info).into()) {
264+
return Some(Err(InvalidTransaction::Custom(
265+
ERR_CONTRACT_CREATION_NOT_ALLOWED,
266+
)
267+
.into()));
268+
}
269+
270+
// TODO: move this code into pallet-block-fees, so it can be used from the production and
271+
// test runtimes.
194272
match self {
195273
RuntimeCall::Ethereum(call) => {
196274
// Withdraw the consensus chain storage fee from the caller and record
@@ -208,8 +286,8 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
208286
Err(_) => return Some(Err(InvalidTransaction::Payment.into())),
209287
}
210288

211-
// Copy from [`pallet_ethereum::Call::pre_dispatch_self_contained`] with `frame_system::CheckWeight`
212-
// replaced to `domain_check_weight::CheckWeight`
289+
// Copied from [`pallet_ethereum::Call::pre_dispatch_self_contained`] with `frame_system::CheckWeight`
290+
// replaced with `domain_check_weight::CheckWeight`
213291
if let pallet_ethereum::Call::transact { transaction } = call {
214292
if let Err(e) = domain_check_weight::CheckWeight::<Runtime>::do_pre_dispatch(
215293
dispatch_info,
@@ -752,6 +830,16 @@ impl pallet_utility::Config for Runtime {
752830
type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>;
753831
}
754832

833+
impl MaybeIntoUtilityCall<Runtime> for RuntimeCall {
834+
/// If this call is a `pallet_utility::Call<Runtime>` call, returns the inner call.
835+
fn maybe_into_utility_call(&self) -> Option<&pallet_utility::Call<Runtime>> {
836+
match self {
837+
RuntimeCall::Utility(call) => Some(call),
838+
_ => None,
839+
}
840+
}
841+
}
842+
755843
// Create the runtime by composing the FRAME pallets that were previously configured.
756844
//
757845
// NOTE: Currently domain runtime does not naturally support the pallets with inherent extrinsics.
@@ -993,6 +1081,7 @@ fn check_transaction_and_do_pre_dispatch_inner(
9931081
pallet_evm_tracker::CheckNonce::from(extra.5 .0),
9941082
extra.6,
9951083
extra.7,
1084+
extra.8,
9961085
);
9971086

9981087
custom_extra

domains/test/service/src/domain.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use domain_service::providers::DefaultProvider;
1515
use domain_service::FullClient;
1616
use domain_test_primitives::{EvmOnchainStateApi, OnchainStateApi};
1717
use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
18-
use frame_system::pallet_prelude::BlockNumberFor;
18+
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
1919
use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi;
2020
use sc_client_api::HeaderBackend;
2121
use sc_domains::RuntimeExecutor;
@@ -399,7 +399,7 @@ where
399399
where
400400
Runtime:
401401
frame_system::Config<Hash = H256> + pallet_transaction_payment::Config + Send + Sync,
402-
Runtime::RuntimeCall:
402+
RuntimeCallFor<Runtime>:
403403
Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
404404
BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
405405
{

domains/test/service/src/lib.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ pub mod chain_spec;
2222
pub mod domain;
2323
pub mod keyring;
2424

25+
pub use domain::*;
2526
use domain_runtime_primitives::opaque::Block;
27+
pub use evm_domain_test_runtime;
2628
use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
27-
use frame_system::pallet_prelude::BlockNumberFor;
29+
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
2830
pub use keyring::Keyring as EcdsaKeyring;
2931
use sc_network::config::{NonReservedPeerMode, TransportConfig};
3032
use sc_network::multiaddr;
@@ -50,9 +52,6 @@ use sp_runtime::traits::Dispatchable;
5052
use std::fmt::{Debug, Display};
5153
use std::str::FromStr;
5254

53-
pub use domain::*;
54-
pub use evm_domain_test_runtime;
55-
5655
/// The domain id of the evm domain
5756
pub const EVM_DOMAIN_ID: DomainId = DomainId::new(0u32);
5857

@@ -185,17 +184,17 @@ type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransact
185184

186185
pub fn construct_extrinsic_raw_payload<Runtime, Client>(
187186
client: impl AsRef<Client>,
188-
function: <Runtime as frame_system::Config>::RuntimeCall,
187+
function: RuntimeCallFor<Runtime>,
189188
immortal: bool,
190189
nonce: u32,
191190
tip: BalanceOf<Runtime>,
192191
) -> (
193-
SignedPayload<<Runtime as frame_system::Config>::RuntimeCall, SignedExtraFor<Runtime>>,
192+
SignedPayload<RuntimeCallFor<Runtime>, SignedExtraFor<Runtime>>,
194193
SignedExtraFor<Runtime>,
195194
)
196195
where
197196
Runtime: frame_system::Config<Hash = H256> + pallet_transaction_payment::Config + Send + Sync,
198-
Runtime::RuntimeCall:
197+
RuntimeCallFor<Runtime>:
199198
Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
200199
BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
201200
u64: From<BlockNumberFor<Runtime>>,
@@ -223,10 +222,7 @@ where
223222
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
224223
);
225224
(
226-
generic::SignedPayload::<
227-
<Runtime as frame_system::Config>::RuntimeCall,
228-
SignedExtraFor<Runtime>,
229-
>::from_raw(
225+
generic::SignedPayload::<RuntimeCallFor<Runtime>, SignedExtraFor<Runtime>>::from_raw(
230226
function,
231227
extra.clone(),
232228
((), 1, 0, genesis_block, current_block_hash, (), (), ()),

0 commit comments

Comments
 (0)