Skip to content

Commit

Permalink
Add contract creation filters to EVM test runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
teor2345 committed Jan 24, 2025
1 parent 388e54d commit 067c829
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 23 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.

1 change: 1 addition & 0 deletions crates/sp-domains-fraud-proof/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ domain-block-builder = { version = "0.1.0", path = "../../domains/client/block-b
domain-block-preprocessor = { version = "0.1.0", path = "../../domains/client/block-preprocessor" }
domain-test-service = { version = "0.1.0", path = "../../domains/test/service" }
ethereum = "0.15.0"
evm-domain-test-runtime = { version = "0.1.0", path = "../../domains/test/runtime/evm" }
fp-rpc = { version = "3.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968" }
fp-self-contained = { version = "1.0.0-dev", git = "https://github.com/autonomys/frontier", rev = "f80f9e2bad338f3bf3854b256b3c4edea23e5968" }
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305" }
Expand Down
19 changes: 16 additions & 3 deletions crates/sp-domains-fraud-proof/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use domain_test_service::evm_domain_test_runtime::{
Runtime as TestRuntime, RuntimeCall, Signature, UncheckedExtrinsic as EvmUncheckedExtrinsic,
};
use domain_test_service::EcdsaKeyring::{Alice, Charlie};
use domain_test_service::EvmDomainNode;
use domain_test_service::Sr25519Keyring::Ferdie;
use domain_test_service::{construct_extrinsic_raw_payload, EvmDomainNode};
use ethereum::TransactionV2 as EthereumTransaction;
use evm_domain_test_runtime::construct_extrinsic_raw_payload;
use fp_rpc::EthereumRuntimeRPCApi;
use rand::distributions::{Distribution, Uniform};
use sc_client_api::{HeaderBackend, StorageProof};
Expand Down Expand Up @@ -127,8 +128,20 @@ async fn benchmark_bundle_with_evm_tx(
value: other_accounts_balance,
}
.into();
let (raw_payload, extra) =
construct_extrinsic_raw_payload(&alice.client, function.clone(), false, 0, 1);

let current_block_hash = alice.client.as_ref().info().best_hash;
let current_block = alice.client.as_ref().info().best_number;
let genesis_block_hash = alice.client.as_ref().hash(0).unwrap().unwrap();

let (raw_payload, extra) = construct_extrinsic_raw_payload(
current_block_hash,
current_block,
genesis_block_hash,
function.clone(),
false,
0,
1,
);
let signature = raw_payload.using_encoded(|e| {
let msg = keccak_256(e);
ecdsa_key.sign_prehashed(&msg)
Expand Down
14 changes: 13 additions & 1 deletion domains/pallets/evm-tracker/src/create_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,21 @@ where
}

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

impl<Runtime> CheckContractCreation<Runtime> {
pub fn new() -> Self {
Self(PhantomData)
}
}

impl<Runtime> Default for CheckContractCreation<Runtime> {
fn default() -> Self {
Self::new()
}
}

// Unsigned calls can't create contracts. Only pallet-evm and pallet-ethereum can create contracts.
// For pallet-evm all contracts are signed extrinsics, for pallet-ethereum there is only one
// extrinsic that is self-contained.
Expand Down
101 changes: 95 additions & 6 deletions domains/test/runtime/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use core::mem;
pub use domain_runtime_primitives::opaque::Header;
use domain_runtime_primitives::{
block_weights, maximum_block_length, maximum_domain_block_weight, EthereumAccountId,
ERR_BALANCE_OVERFLOW, ERR_NONCE_OVERFLOW, EXISTENTIAL_DEPOSIT, SLOT_DURATION,
ERR_BALANCE_OVERFLOW, ERR_CONTRACT_CREATION_NOT_ALLOWED, ERR_NONCE_OVERFLOW,
EXISTENTIAL_DEPOSIT, SLOT_DURATION,
};
pub use domain_runtime_primitives::{
opaque, Balance, BlockNumber, CheckExtrinsicsValidityError, DecodeExtrinsicError,
Expand All @@ -38,6 +39,7 @@ use frame_support::weights::constants::{ParityDbWeight, WEIGHT_REF_TIME_PER_SECO
use frame_support::weights::{ConstantMultiplier, Weight};
use frame_support::{construct_runtime, parameter_types};
use frame_system::limits::{BlockLength, BlockWeights};
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
use pallet_block_fees::fees::OnChargeDomainTransaction;
use pallet_ethereum::Call::transact;
use pallet_ethereum::{
Expand All @@ -47,6 +49,7 @@ use pallet_evm::{
Account as EVMAccount, EnsureAddressNever, EnsureAddressRoot, FeeCalculator,
IdentityAddressMapping, Runner,
};
use pallet_evm_tracker::create_contract::is_create_contract_allowed;
use pallet_evm_tracker::traits::{MaybeIntoEthCall, MaybeIntoEvmCall};
use pallet_transporter::EndpointHandler;
use sp_api::impl_runtime_apis;
Expand All @@ -61,7 +64,7 @@ use sp_messenger::messages::{
use sp_messenger::{ChannelNonce, XdmId};
use sp_messenger_host_functions::{get_storage_key, StorageKeyRequest};
use sp_mmr_primitives::EncodableOpaqueLeaf;
use sp_runtime::generic::Era;
use sp_runtime::generic::{Era, SignedPayload};
use sp_runtime::traits::{
BlakeTwo256, Block as BlockT, Checkable, DispatchInfoOf, Dispatchable, IdentityLookup,
Keccak256, NumberFor, One, PostDispatchInfoOf, SignedExtension, UniqueSaturatedInto,
Expand All @@ -72,7 +75,7 @@ use sp_runtime::transaction_validity::{
};
use sp_runtime::{
generic, impl_opaque_keys, ApplyExtrinsicResult, ConsensusEngineId, Digest,
ExtrinsicInclusionMode,
ExtrinsicInclusionMode, SaturatedConversion,
};
pub use sp_runtime::{MultiAddress, Perbill, Permill};
use sp_std::cmp::{max, Ordering};
Expand All @@ -84,6 +87,7 @@ use sp_subspace_mmr::domain_mmr_runtime_interface::{
};
use sp_subspace_mmr::{ConsensusChainMmrLeafProof, MmrLeaf};
use sp_version::RuntimeVersion;
use subspace_runtime_primitives::utility::MaybeIntoUtilityCall;
use subspace_runtime_primitives::{
BlockNumber as ConsensusBlockNumber, Hash as ConsensusBlockHash, Moment, SHANNON, SSC,
};
Expand Down Expand Up @@ -113,6 +117,7 @@ pub type SignedExtra = (
frame_system::CheckNonce<Runtime>,
domain_check_weight::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_evm_tracker::create_contract::CheckContractCreation<Runtime>,
);

/// Custom signed extra for check_and_pre_dispatch.
Expand All @@ -126,6 +131,7 @@ type CustomSignedExtra = (
pallet_evm_tracker::CheckNonce<Runtime>,
domain_check_weight::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
pallet_evm_tracker::create_contract::CheckContractCreation<Runtime>,
);

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

type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;

pub fn construct_extrinsic_raw_payload(
current_block_hash: H256,
current_block: BlockNumberFor<Runtime>,
genesis_block_hash: H256,
function: RuntimeCallFor<Runtime>,
immortal: bool,
nonce: u32,
tip: BalanceOf<Runtime>,
) -> (
SignedPayload<RuntimeCallFor<Runtime>, SignedExtra>,
SignedExtra,
) {
let current_block = current_block.saturated_into();
let period = u64::from(<Runtime as frame_system::Config>::BlockHashCount::get())
.checked_next_power_of_two()
.map(|c| c / 2)
.unwrap_or(2);
let extra: SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckMortality::<Runtime>::from(if immortal {
generic::Era::Immortal
} else {
generic::Era::mortal(period, current_block)
}),
frame_system::CheckNonce::<Runtime>::from(nonce),
domain_check_weight::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
pallet_evm_tracker::create_contract::CheckContractCreation::<Runtime>::new(),
);
(
generic::SignedPayload::<RuntimeCallFor<Runtime>, SignedExtra>::from_raw(
function,
extra.clone(),
(
(),
1,
0,
genesis_block_hash,
current_block_hash,
(),
(),
(),
(),
),
),
extra,
)
}

/// Executive: handles dispatch to the various modules.
pub type Executive = domain_pallet_executive::Executive<
Runtime,
Expand Down Expand Up @@ -167,9 +227,18 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
dispatch_info: &DispatchInfoOf<RuntimeCall>,
len: usize,
) -> Option<TransactionValidity> {
if !is_create_contract_allowed::<Runtime>(self, &(*info).into()) {
return Some(Err(InvalidTransaction::Custom(
ERR_CONTRACT_CREATION_NOT_ALLOWED,
)
.into()));
}

// TODO: move this code into pallet-block-fees, so it can be used from the production and
// test runtimes.
match self {
RuntimeCall::Ethereum(call) => {
// Ensure the caller can pay the consensus chain storage fee
// Ensure the caller can pay for the consensus chain storage fee
let consensus_storage_fee =
BlockFees::consensus_chain_byte_fee().checked_mul(Balance::from(len as u32))?;
let withdraw_res = <InnerEVMCurrencyAdapter as pallet_evm::OnChargeEVMTransaction<
Expand All @@ -191,6 +260,15 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
dispatch_info: &DispatchInfoOf<RuntimeCall>,
len: usize,
) -> Option<Result<(), TransactionValidityError>> {
if !is_create_contract_allowed::<Runtime>(self, &(*info).into()) {
return Some(Err(InvalidTransaction::Custom(
ERR_CONTRACT_CREATION_NOT_ALLOWED,
)
.into()));
}

// TODO: move this code into pallet-block-fees, so it can be used from the production and
// test runtimes.
match self {
RuntimeCall::Ethereum(call) => {
// Withdraw the consensus chain storage fee from the caller and record
Expand All @@ -208,8 +286,8 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall {
Err(_) => return Some(Err(InvalidTransaction::Payment.into())),
}

// Copy from [`pallet_ethereum::Call::pre_dispatch_self_contained`] with `frame_system::CheckWeight`
// replaced to `domain_check_weight::CheckWeight`
// Copied from [`pallet_ethereum::Call::pre_dispatch_self_contained`] with `frame_system::CheckWeight`
// replaced with `domain_check_weight::CheckWeight`
if let pallet_ethereum::Call::transact { transaction } = call {
if let Err(e) = domain_check_weight::CheckWeight::<Runtime>::do_pre_dispatch(
dispatch_info,
Expand Down Expand Up @@ -752,6 +830,16 @@ impl pallet_utility::Config for Runtime {
type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>;
}

impl MaybeIntoUtilityCall<Runtime> for RuntimeCall {
/// If this call is a `pallet_utility::Call<Runtime>` call, returns the inner call.
fn maybe_into_utility_call(&self) -> Option<&pallet_utility::Call<Runtime>> {
match self {
RuntimeCall::Utility(call) => Some(call),
_ => None,
}
}
}

// Create the runtime by composing the FRAME pallets that were previously configured.
//
// NOTE: Currently domain runtime does not naturally support the pallets with inherent extrinsics.
Expand Down Expand Up @@ -993,6 +1081,7 @@ fn check_transaction_and_do_pre_dispatch_inner(
pallet_evm_tracker::CheckNonce::from(extra.5 .0),
extra.6,
extra.7,
extra.8,
);

custom_extra
Expand Down
4 changes: 2 additions & 2 deletions domains/test/service/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use domain_service::providers::DefaultProvider;
use domain_service::FullClient;
use domain_test_primitives::{EvmOnchainStateApi, OnchainStateApi};
use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
use frame_system::pallet_prelude::BlockNumberFor;
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
use pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi;
use sc_client_api::HeaderBackend;
use sc_domains::RuntimeExecutor;
Expand Down Expand Up @@ -399,7 +399,7 @@ where
where
Runtime:
frame_system::Config<Hash = H256> + pallet_transaction_payment::Config + Send + Sync,
Runtime::RuntimeCall:
RuntimeCallFor<Runtime>:
Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
{
Expand Down
18 changes: 7 additions & 11 deletions domains/test/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ pub mod chain_spec;
pub mod domain;
pub mod keyring;

pub use domain::*;
use domain_runtime_primitives::opaque::Block;
pub use evm_domain_test_runtime;
use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
use frame_system::pallet_prelude::BlockNumberFor;
use frame_system::pallet_prelude::{BlockNumberFor, RuntimeCallFor};
pub use keyring::Keyring as EcdsaKeyring;
use sc_network::config::{NonReservedPeerMode, TransportConfig};
use sc_network::multiaddr;
Expand All @@ -50,9 +52,6 @@ use sp_runtime::traits::Dispatchable;
use std::fmt::{Debug, Display};
use std::str::FromStr;

pub use domain::*;
pub use evm_domain_test_runtime;

/// The domain id of the evm domain
pub const EVM_DOMAIN_ID: DomainId = DomainId::new(0u32);

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

pub fn construct_extrinsic_raw_payload<Runtime, Client>(
client: impl AsRef<Client>,
function: <Runtime as frame_system::Config>::RuntimeCall,
function: RuntimeCallFor<Runtime>,
immortal: bool,
nonce: u32,
tip: BalanceOf<Runtime>,
) -> (
SignedPayload<<Runtime as frame_system::Config>::RuntimeCall, SignedExtraFor<Runtime>>,
SignedPayload<RuntimeCallFor<Runtime>, SignedExtraFor<Runtime>>,
SignedExtraFor<Runtime>,
)
where
Runtime: frame_system::Config<Hash = H256> + pallet_transaction_payment::Config + Send + Sync,
Runtime::RuntimeCall:
RuntimeCallFor<Runtime>:
Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + Send + Sync,
BalanceOf<Runtime>: Send + Sync + From<u64> + sp_runtime::FixedPointOperand,
u64: From<BlockNumberFor<Runtime>>,
Expand Down Expand Up @@ -223,10 +222,7 @@ where
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
);
(
generic::SignedPayload::<
<Runtime as frame_system::Config>::RuntimeCall,
SignedExtraFor<Runtime>,
>::from_raw(
generic::SignedPayload::<RuntimeCallFor<Runtime>, SignedExtraFor<Runtime>>::from_raw(
function,
extra.clone(),
((), 1, 0, genesis_block, current_block_hash, (), (), ()),
Expand Down

0 comments on commit 067c829

Please sign in to comment.