#![cfg_attr(not(feature = "std"), no_std)]
#![recursion_limit = "256"]
#![allow(clippy::new_without_default, clippy::or_fun_call)]
#![cfg_attr(feature = "runtime-benchmarks", warn(unused_crate_dependencies))]
extern crate alloc;
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use alloc::{borrow::Cow, vec, vec::Vec};
use core::marker::PhantomData;
use scale_codec::{Decode, Encode};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
use sp_core::{
crypto::{ByteArray, KeyTypeId},
ConstU128, OpaqueMetadata, H160, H256, U256,
};
use sp_runtime::{
generic, impl_opaque_keys,
traits::{
BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, Get, IdentifyAccount,
IdentityLookup, NumberFor, PostDispatchInfoOf, UniqueSaturatedInto, Verify,
},
transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
ApplyExtrinsicResult, ConsensusEngineId, ExtrinsicInclusionMode, Perbill, Permill,
};
use sp_version::RuntimeVersion;
#[cfg(feature = "with-paritydb-weights")]
use frame_support::weights::constants::ParityDbWeight as RuntimeDbWeight;
#[cfg(feature = "with-rocksdb-weights")]
use frame_support::weights::constants::RocksDbWeight as RuntimeDbWeight;
use frame_support::{
derive_impl,
genesis_builder_helper::{build_state, get_preset},
parameter_types,
traits::{ConstBool, ConstU32, ConstU64, ConstU8, FindAuthor, OnFinalize, OnTimestampSet},
weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, IdentityFee, Weight},
};
use pallet_transaction_payment::FungibleAdapter;
use polkadot_runtime_common::SlowAdjustingFeeUpdate;
use sp_genesis_builder::PresetId;
use fp_account::EthereumSignature;
use fp_evm::weight_per_gas;
use fp_rpc::TransactionStatus;
use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction};
use pallet_evm::{
Account as EVMAccount, EnsureAccountId20, FeeCalculator, IdentityAddressMapping, Runner,
};
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
mod precompiles;
use precompiles::FrontierPrecompiles;
pub type BlockNumber = u32;
pub type Signature = EthereumSignature;
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
pub type AccountIndex = u32;
pub type Balance = u128;
pub type Nonce = u32;
pub type Hash = H256;
pub type Hashing = BlakeTwo256;
pub type DigestItem = generic::DigestItem;
pub type Address = AccountId;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type SignedBlock = generic::SignedBlock<Block>;
pub type BlockId = generic::BlockId<Block>;
pub type SignedExtra = cumulus_pallet_weight_reclaim::StorageWeightReclaim<
Runtime,
(
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
),
>;
pub type UncheckedExtrinsic =
fp_self_contained::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
pub type CheckedExtrinsic =
fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra, H160>;
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
>;
pub const MILLISECS_PER_BLOCK: u64 = 6000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
pub mod opaque {
use super::*;
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type BlockId = generic::BlockId<Block>;
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
pub grandpa: Grandpa,
}
}
}
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: Cow::Borrowed("frontier-template"),
impl_name: Cow::Borrowed("frontier-template"),
authoring_version: 1,
spec_version: 1,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
system_version: 1,
};
#[cfg(feature = "std")]
pub fn native_version() -> sp_version::NativeVersion {
sp_version::NativeVersion {
runtime_version: VERSION,
can_author_with: Default::default(),
}
}
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 2000;
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS,
u64::MAX,
);
pub const MAXIMUM_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
parameter_types! {
pub const Version: RuntimeVersion = VERSION;
pub const BlockHashCount: BlockNumber = 256;
pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights
::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO);
pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
::max_with_normal_ratio(MAXIMUM_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
pub const SS58Prefix: u8 = 42;
}
#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for Runtime {
type BlockWeights = BlockWeights;
type BlockLength = BlockLength;
type Nonce = Nonce;
type Hash = Hash;
type Hashing = Hashing;
type AccountId = AccountId;
type Lookup = IdentityLookup<AccountId>;
type Block = Block;
type BlockHashCount = BlockHashCount;
type DbWeight = RuntimeDbWeight;
type Version = Version;
type AccountData = pallet_balances::AccountData<Balance>;
type SS58Prefix = SS58Prefix;
type MaxConsumers = ConstU32<16>;
}
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
type MaxAuthorities = ConstU32<32>;
type DisabledValidators = ();
type AllowMultipleBlocksPerSlot = ConstBool<false>;
type SlotDuration = pallet_aura::MinimumPeriodTimesTwo<Runtime>;
}
impl pallet_grandpa::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type MaxAuthorities = ConstU32<32>;
type MaxNominators = ConstU32<0>;
type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = ();
}
impl cumulus_pallet_weight_reclaim::Config for Runtime {
type WeightInfo = ();
}
parameter_types! {
pub storage EnableManualSeal: bool = false;
}
pub struct ConsensusOnTimestampSet<T>(PhantomData<T>);
impl<T: pallet_aura::Config> OnTimestampSet<T::Moment> for ConsensusOnTimestampSet<T> {
fn on_timestamp_set(moment: T::Moment) {
if EnableManualSeal::get() {
return;
}
<pallet_aura::Pallet<T> as OnTimestampSet<T::Moment>>::on_timestamp_set(moment)
}
}
impl pallet_timestamp::Config for Runtime {
type Moment = u64;
type OnTimestampSet = ConsensusOnTimestampSet<Self>;
type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
type WeightInfo = ();
}
pub const EXISTENTIAL_DEPOSIT: u128 = 0;
impl pallet_balances::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeHoldReason = RuntimeHoldReason;
type RuntimeFreezeReason = RuntimeFreezeReason;
type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
type Balance = Balance;
type DustRemoval = ();
type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
type AccountStore = System;
type ReserveIdentifier = [u8; 8];
type FreezeIdentifier = RuntimeFreezeReason;
type MaxLocks = ConstU32<50>;
type MaxReserves = ConstU32<50>;
type MaxFreezes = ConstU32<1>;
type DoneSlashHandler = ();
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = FungibleAdapter<Balances, ()>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Runtime>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
}
impl pallet_sudo::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = pallet_sudo::weights::SubstrateWeight<Self>;
}
impl pallet_evm_chain_id::Config for Runtime {}
pub struct FindAuthorTruncated<F>(PhantomData<F>);
impl<F: FindAuthor<u32>> FindAuthor<H160> for FindAuthorTruncated<F> {
fn find_author<'a, I>(digests: I) -> Option<H160>
where
I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
{
if let Some(author_index) = F::find_author(digests) {
let authority_id =
pallet_aura::Authorities::<Runtime>::get()[author_index as usize].clone();
return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
}
None
}
}
const BLOCK_GAS_LIMIT: u64 = 75_000_000;
const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
const MAX_STORAGE_GROWTH: u64 = 400 * 1024;
parameter_types! {
pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
pub const GasLimitPovSizeRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_POV_SIZE);
pub const GasLimitStorageGrowthRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_STORAGE_GROWTH);
pub PrecompilesValue: FrontierPrecompiles<Runtime> = FrontierPrecompiles::<_>::new();
pub WeightPerGas: Weight = Weight::from_parts(weight_per_gas(BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK), 0);
}
impl pallet_evm::Config for Runtime {
type AccountProvider = pallet_evm::FrameSystemAccountProvider<Self>;
type FeeCalculator = BaseFee;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
type CallOrigin = EnsureAccountId20;
type WithdrawOrigin = EnsureAccountId20;
type AddressMapping = IdentityAddressMapping;
type Currency = Balances;
type RuntimeEvent = RuntimeEvent;
type PrecompilesType = FrontierPrecompiles<Self>;
type PrecompilesValue = PrecompilesValue;
type ChainId = EVMChainId;
type BlockGasLimit = BlockGasLimit;
type Runner = pallet_evm::runner::stack::Runner<Self>;
type OnChargeTransaction = ();
type OnCreate = ();
type FindAuthor = FindAuthorTruncated<Aura>;
type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
type Timestamp = Timestamp;
type CreateOriginFilter = ();
type CreateInnerOriginFilter = ();
type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;
}
parameter_types! {
pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes;
}
impl pallet_ethereum::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type StateRoot = pallet_ethereum::IntermediateStateRoot<Self::Version>;
type PostLogContent = PostBlockAndTxnHashes;
type ExtraDataLength = ConstU32<30>;
}
parameter_types! {
pub BoundDivision: U256 = U256::from(1024);
}
impl pallet_dynamic_fee::Config for Runtime {
type MinGasPriceBoundDivisor = BoundDivision;
}
parameter_types! {
pub DefaultBaseFeePerGas: U256 = U256::from(1_000_000_000);
pub DefaultElasticity: Permill = Permill::from_parts(125_000);
}
pub struct BaseFeeThreshold;
impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
fn lower() -> Permill {
Permill::zero()
}
fn ideal() -> Permill {
Permill::from_parts(500_000)
}
fn upper() -> Permill {
Permill::from_parts(1_000_000)
}
}
impl pallet_base_fee::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Threshold = BaseFeeThreshold;
type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
type DefaultElasticity = DefaultElasticity;
}
#[frame_support::pallet]
pub mod pallet_manual_seal {
use super::*;
use frame_support::pallet_prelude::*;
#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);
#[pallet::config]
pub trait Config: frame_system::Config {}
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T> {
pub enable: bool,
#[serde(skip)]
pub _config: PhantomData<T>,
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
EnableManualSeal::set(&self.enable);
}
}
}
impl pallet_manual_seal::Config for Runtime {}
#[frame_support::runtime]
mod runtime {
#[runtime::runtime]
#[runtime::derive(
RuntimeEvent,
RuntimeCall,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask
)]
pub struct Runtime;
#[runtime::pallet_index(0)]
pub type System = frame_system;
#[runtime::pallet_index(1)]
pub type Timestamp = pallet_timestamp;
#[runtime::pallet_index(2)]
pub type Aura = pallet_aura;
#[runtime::pallet_index(3)]
pub type Grandpa = pallet_grandpa;
#[runtime::pallet_index(4)]
pub type Balances = pallet_balances;
#[runtime::pallet_index(5)]
pub type TransactionPayment = pallet_transaction_payment;
#[runtime::pallet_index(6)]
pub type Sudo = pallet_sudo;
#[runtime::pallet_index(7)]
pub type Ethereum = pallet_ethereum;
#[runtime::pallet_index(8)]
pub type EVM = pallet_evm;
#[runtime::pallet_index(9)]
pub type EVMChainId = pallet_evm_chain_id;
#[runtime::pallet_index(10)]
pub type BaseFee = pallet_base_fee;
#[runtime::pallet_index(11)]
pub type ManualSeal = pallet_manual_seal;
}
#[derive(Clone)]
pub struct TransactionConverter<B>(PhantomData<B>);
impl<B> Default for TransactionConverter<B> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<B: BlockT> fp_rpc::ConvertTransaction<<B as BlockT>::Extrinsic> for TransactionConverter<B> {
fn convert_transaction(
&self,
transaction: pallet_ethereum::Transaction,
) -> <B as BlockT>::Extrinsic {
let extrinsic = UncheckedExtrinsic::new_bare(
pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
);
let encoded = extrinsic.encode();
<B as BlockT>::Extrinsic::decode(&mut &encoded[..])
.expect("Encoded extrinsic is always valid")
}
}
impl fp_self_contained::SelfContainedCall for RuntimeCall {
type SignedInfo = H160;
fn is_self_contained(&self) -> bool {
match self {
RuntimeCall::Ethereum(call) => call.is_self_contained(),
_ => false,
}
}
fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
match self {
RuntimeCall::Ethereum(call) => call.check_self_contained(),
_ => None,
}
}
fn validate_self_contained(
&self,
info: &Self::SignedInfo,
dispatch_info: &DispatchInfoOf<RuntimeCall>,
len: usize,
) -> Option<TransactionValidity> {
match self {
RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
_ => None,
}
}
fn pre_dispatch_self_contained(
&self,
info: &Self::SignedInfo,
dispatch_info: &DispatchInfoOf<RuntimeCall>,
len: usize,
) -> Option<Result<(), TransactionValidityError>> {
match self {
RuntimeCall::Ethereum(call) => {
call.pre_dispatch_self_contained(info, dispatch_info, len)
}
_ => None,
}
}
fn apply_self_contained(
self,
info: Self::SignedInfo,
) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
match self {
call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => {
Some(call.dispatch(RuntimeOrigin::from(
pallet_ethereum::RawOrigin::EthereumTransaction(info),
)))
}
_ => None,
}
}
}
#[cfg(feature = "runtime-benchmarks")]
mod benches {
frame_benchmarking::define_benchmarks!(
[frame_benchmarking, BaselineBench::<Runtime>]
[frame_system, SystemBench::<Runtime>]
[pallet_balances, Balances]
[pallet_timestamp, Timestamp]
[pallet_sudo, Sudo]
[pallet_evm, EVM]
);
}
impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn execute_block(block: Block) {
Executive::execute_block(block)
}
fn initialize_block(header: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode {
Executive::initialize_block(header)
}
}
impl sp_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
OpaqueMetadata::new(Runtime::metadata().into())
}
fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
Runtime::metadata_at_version(version)
}
fn metadata_versions() -> Vec<u32> {
Runtime::metadata_versions()
}
}
impl sp_block_builder::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
Executive::apply_extrinsic(extrinsic)
}
fn finalize_block() -> <Block as BlockT>::Header {
Executive::finalize_block()
}
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics()
}
fn check_inherents(
block: Block,
data: sp_inherents::InherentData,
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
tx: <Block as BlockT>::Extrinsic,
block_hash: <Block as BlockT>::Hash,
) -> TransactionValidity {
Executive::validate_transaction(source, tx, block_hash)
}
}
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &<Block as BlockT>::Header) {
Executive::offchain_worker(header)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
build_state::<RuntimeGenesisConfig>(config)
}
fn get_preset(id: &Option<PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, |_| None)
}
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
vec![]
}
}
impl sp_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
opaque::SessionKeys::generate(seed)
}
fn decode_session_keys(
encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
}
}
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
}
fn authorities() -> Vec<AuraId> {
pallet_aura::Authorities::<Runtime>::get().into_inner()
}
}
impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
fn grandpa_authorities() -> GrandpaAuthorityList {
Grandpa::grandpa_authorities()
}
fn current_set_id() -> sp_consensus_grandpa::SetId {
Grandpa::current_set_id()
}
fn submit_report_equivocation_unsigned_extrinsic(
_equivocation_proof: sp_consensus_grandpa::EquivocationProof<
<Block as BlockT>::Hash,
NumberFor<Block>,
>,
_key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
}
fn generate_key_ownership_proof(
_set_id: sp_consensus_grandpa::SetId,
_authority_id: GrandpaId,
) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
None
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
fn account_nonce(account: AccountId) -> Nonce {
System::account_nonce(account)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
Block,
Balance,
> for Runtime {
fn query_info(
uxt: <Block as BlockT>::Extrinsic,
len: u32
) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_info(uxt, len)
}
fn query_fee_details(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_fee_details(uxt, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
fn chain_id() -> u64 {
<Runtime as pallet_evm::Config>::ChainId::get()
}
fn account_basic(address: H160) -> EVMAccount {
let (account, _) = pallet_evm::Pallet::<Runtime>::account_basic(&address);
account
}
fn gas_price() -> U256 {
let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
gas_price
}
fn account_code_at(address: H160) -> Vec<u8> {
pallet_evm::AccountCodes::<Runtime>::get(address)
}
fn author() -> H160 {
<pallet_evm::Pallet<Runtime>>::find_author()
}
fn storage_at(address: H160, index: U256) -> H256 {
pallet_evm::AccountStorages::<Runtime>::get(address, H256::from(index.to_big_endian()))
}
fn call(
from: H160,
to: H160,
data: Vec<u8>,
value: U256,
gas_limit: U256,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
nonce: Option<U256>,
estimate: bool,
access_list: Option<Vec<(H160, Vec<H256>)>>,
) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
use pallet_evm::GasWeightMapping as _;
let config = if estimate {
let mut config = <Runtime as pallet_evm::Config>::config().clone();
config.estimate = true;
Some(config)
} else {
None
};
let mut estimated_transaction_len = data.len() +
258;
if access_list.is_some() {
estimated_transaction_len += access_list.encoded_size();
}
let gas_limit = if gas_limit > U256::from(u64::MAX) {
u64::MAX
} else {
gas_limit.low_u64()
};
let without_base_extrinsic_weight = true;
let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};
<Runtime as pallet_evm::Config>::Runner::call(
from,
to,
data,
value,
gas_limit.unique_saturated_into(),
max_fee_per_gas,
max_priority_fee_per_gas,
nonce,
access_list.unwrap_or_default(),
false,
true,
weight_limit,
proof_size_base_cost,
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
fn create(
from: H160,
data: Vec<u8>,
value: U256,
gas_limit: U256,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
nonce: Option<U256>,
estimate: bool,
access_list: Option<Vec<(H160, Vec<H256>)>>,
) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
use pallet_evm::GasWeightMapping as _;
let config = if estimate {
let mut config = <Runtime as pallet_evm::Config>::config().clone();
config.estimate = true;
Some(config)
} else {
None
};
let mut estimated_transaction_len = data.len() +
190;
if max_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if max_priority_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if access_list.is_some() {
estimated_transaction_len += access_list.encoded_size();
}
let gas_limit = if gas_limit > U256::from(u64::MAX) {
u64::MAX
} else {
gas_limit.low_u64()
};
let without_base_extrinsic_weight = true;
let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};
<Runtime as pallet_evm::Config>::Runner::create(
from,
data,
value,
gas_limit.unique_saturated_into(),
max_fee_per_gas,
max_priority_fee_per_gas,
nonce,
access_list.unwrap_or_default(),
false,
true,
weight_limit,
proof_size_base_cost,
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}
fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
}
fn current_block() -> Option<pallet_ethereum::Block> {
pallet_ethereum::CurrentBlock::<Runtime>::get()
}
fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
pallet_ethereum::CurrentReceipts::<Runtime>::get()
}
fn current_all() -> (
Option<pallet_ethereum::Block>,
Option<Vec<pallet_ethereum::Receipt>>,
Option<Vec<TransactionStatus>>
) {
(
pallet_ethereum::CurrentBlock::<Runtime>::get(),
pallet_ethereum::CurrentReceipts::<Runtime>::get(),
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
)
}
fn extrinsic_filter(
xts: Vec<<Block as BlockT>::Extrinsic>,
) -> Vec<EthereumTransaction> {
xts.into_iter().filter_map(|xt| match xt.0.function {
RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
_ => None
}).collect::<Vec<EthereumTransaction>>()
}
fn elasticity() -> Option<Permill> {
Some(pallet_base_fee::Elasticity::<Runtime>::get())
}
fn gas_limit_multiplier_support() {}
fn pending_block(
xts: Vec<<Block as BlockT>::Extrinsic>,
) -> (Option<pallet_ethereum::Block>, Option<Vec<TransactionStatus>>) {
for ext in xts.into_iter() {
let _ = Executive::apply_extrinsic(ext);
}
Ethereum::on_finalize(System::block_number() + 1);
(
pallet_ethereum::CurrentBlock::<Runtime>::get(),
pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
)
}
fn initialize_pending_block(header: &<Block as BlockT>::Header) {
Executive::initialize_block(header);
}
}
impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
fn convert_transaction(transaction: EthereumTransaction) -> <Block as BlockT>::Extrinsic {
UncheckedExtrinsic::new_bare(
pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
)
}
}
#[cfg(feature = "runtime-benchmarks")]
impl frame_benchmarking::Benchmark<Block> for Runtime {
fn benchmark_metadata(extra: bool) -> (
Vec<frame_benchmarking::BenchmarkList>,
Vec<frame_support::traits::StorageInfo>,
) {
use frame_benchmarking::{baseline, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
use baseline::Pallet as BaselineBench;
use frame_system_benchmarking::Pallet as SystemBench;
let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra);
let storage_info = AllPalletsWithSystem::storage_info();
(list, storage_info)
}
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
use frame_benchmarking::{baseline, BenchmarkBatch};
use frame_support::traits::TrackedStorageKey;
use baseline::Pallet as BaselineBench;
use frame_system_benchmarking::Pallet as SystemBench;
impl baseline::Config for Runtime {}
impl frame_system_benchmarking::Config for Runtime {}
let whitelist: Vec<TrackedStorageKey> = Vec::new();
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
add_benchmarks!(params, batches);
Ok(batches)
}
}
}
#[cfg(test)]
mod tests {
use super::{Runtime, WeightPerGas};
#[test]
fn configured_base_extrinsic_weight_is_evm_compatible() {
let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000;
let base_extrinsic = <Runtime as frame_system::Config>::BlockWeights::get()
.get(frame_support::dispatch::DispatchClass::Normal)
.base_extrinsic;
assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time());
}
}