frontier_template_runtime/
lib.rs

1//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
5#![recursion_limit = "256"]
6#![allow(clippy::new_without_default, clippy::or_fun_call)]
7#![cfg_attr(feature = "runtime-benchmarks", warn(unused_crate_dependencies))]
8
9extern crate alloc;
10
11mod genesis_config_preset;
12mod precompiles;
13mod weights;
14
15// Make the WASM binary available.
16#[cfg(feature = "std")]
17include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
18
19use alloc::{borrow::Cow, vec, vec::Vec};
20use core::marker::PhantomData;
21use ethereum::AuthorizationList;
22use scale_codec::{Decode, Encode};
23use sp_api::impl_runtime_apis;
24use sp_consensus_aura::sr25519::AuthorityId as AuraId;
25use sp_consensus_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
26use sp_core::{
27	crypto::{ByteArray, KeyTypeId},
28	ConstU128, OpaqueMetadata, H160, H256, U256,
29};
30use sp_runtime::{
31	generic, impl_opaque_keys,
32	traits::{
33		BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, Get, IdentifyAccount,
34		IdentityLookup, NumberFor, PostDispatchInfoOf, UniqueSaturatedInto, Verify,
35	},
36	transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
37	ApplyExtrinsicResult, ConsensusEngineId, ExtrinsicInclusionMode, Perbill, Permill,
38};
39use sp_version::RuntimeVersion;
40// Substrate FRAME
41#[cfg(feature = "with-paritydb-weights")]
42use frame_support::weights::constants::ParityDbWeight as RuntimeDbWeight;
43#[cfg(feature = "with-rocksdb-weights")]
44use frame_support::weights::constants::RocksDbWeight as RuntimeDbWeight;
45use frame_support::{
46	derive_impl,
47	genesis_builder_helper::build_state,
48	parameter_types,
49	traits::{ConstBool, ConstU32, ConstU64, ConstU8, FindAuthor, OnFinalize, OnTimestampSet},
50	weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, IdentityFee, Weight},
51};
52use pallet_transaction_payment::FungibleAdapter;
53use polkadot_runtime_common::SlowAdjustingFeeUpdate;
54use sp_genesis_builder::PresetId;
55// Frontier
56use fp_account::EthereumSignature;
57use fp_evm::weight_per_gas;
58use fp_rpc::TransactionStatus;
59use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction};
60use pallet_evm::{
61	Account as EVMAccount, EnsureAccountId20, FeeCalculator, IdentityAddressMapping, Runner,
62};
63
64// A few exports that help ease life for downstream crates.
65pub use frame_system::Call as SystemCall;
66pub use pallet_balances::Call as BalancesCall;
67pub use pallet_timestamp::Call as TimestampCall;
68
69use precompiles::FrontierPrecompiles;
70
71/// Type of block number.
72pub type BlockNumber = u32;
73
74/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
75pub type Signature = EthereumSignature;
76
77/// Some way of identifying an account on the chain. We intentionally make it equivalent
78/// to the public key of our transaction signing scheme.
79pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
80
81/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
82/// never know...
83pub type AccountIndex = u32;
84
85/// Balance of an account.
86pub type Balance = u128;
87
88/// Index of a transaction in the chain.
89pub type Nonce = u32;
90
91/// A hash of some data used by the chain.
92pub type Hash = H256;
93
94/// The hashing algorithm used by the chain.
95pub type Hashing = BlakeTwo256;
96
97/// Digest item type.
98pub type DigestItem = generic::DigestItem;
99
100/// The address format for describing accounts.
101pub type Address = AccountId;
102
103/// Block header type as expected by this runtime.
104pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
105
106/// Block type as expected by this runtime.
107pub type Block = generic::Block<Header, UncheckedExtrinsic>;
108
109/// A Block signed with a Justification
110pub type SignedBlock = generic::SignedBlock<Block>;
111
112/// BlockId type as expected by this runtime.
113pub type BlockId = generic::BlockId<Block>;
114
115/// The SignedExtension to the basic transaction logic.
116pub type SignedExtra = cumulus_pallet_weight_reclaim::StorageWeightReclaim<
117	Runtime,
118	(
119		frame_system::CheckNonZeroSender<Runtime>,
120		frame_system::CheckSpecVersion<Runtime>,
121		frame_system::CheckTxVersion<Runtime>,
122		frame_system::CheckGenesis<Runtime>,
123		frame_system::CheckEra<Runtime>,
124		frame_system::CheckNonce<Runtime>,
125		frame_system::CheckWeight<Runtime>,
126		pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
127	),
128>;
129
130/// Unchecked extrinsic type as expected by this runtime.
131pub type UncheckedExtrinsic =
132	fp_self_contained::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
133
134/// Extrinsic type that has already been checked.
135pub type CheckedExtrinsic =
136	fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra, H160>;
137
138/// The payload being signed in transactions.
139pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
140
141/// Executive: handles dispatch to the various modules.
142pub type Executive = frame_executive::Executive<
143	Runtime,
144	Block,
145	frame_system::ChainContext<Runtime>,
146	Runtime,
147	AllPalletsWithSystem,
148>;
149
150// Time is measured by number of blocks.
151pub const MILLISECS_PER_BLOCK: u64 = 6000;
152pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
153pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
154pub const HOURS: BlockNumber = MINUTES * 60;
155pub const DAYS: BlockNumber = HOURS * 24;
156
157/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
158/// the specifics of the runtime. They can then be made to be agnostic over specific formats
159/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
160/// to even the core data structures.
161pub mod opaque {
162	use super::*;
163
164	pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
165
166	/// Opaque block header type.
167	pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
168	/// Opaque block type.
169	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
170	/// Opaque block identifier type.
171	pub type BlockId = generic::BlockId<Block>;
172
173	impl_opaque_keys! {
174		pub struct SessionKeys {
175			pub aura: Aura,
176			pub grandpa: Grandpa,
177		}
178	}
179}
180
181#[sp_version::runtime_version]
182pub const VERSION: RuntimeVersion = RuntimeVersion {
183	spec_name: Cow::Borrowed("frontier-template"),
184	impl_name: Cow::Borrowed("frontier-template"),
185	authoring_version: 1,
186	spec_version: 1,
187	impl_version: 1,
188	apis: RUNTIME_API_VERSIONS,
189	transaction_version: 1,
190	system_version: 1,
191};
192
193/// The version information used to identify this runtime when compiled natively.
194#[cfg(feature = "std")]
195pub fn native_version() -> sp_version::NativeVersion {
196	sp_version::NativeVersion {
197		runtime_version: VERSION,
198		can_author_with: Default::default(),
199	}
200}
201
202const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
203/// We allow for 2000ms of compute with a 6 second average block time.
204pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 2000;
205pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
206	WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS,
207	u64::MAX,
208);
209pub const MAXIMUM_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
210
211parameter_types! {
212	pub const Version: RuntimeVersion = VERSION;
213	pub const BlockHashCount: BlockNumber = 256;
214	pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights
215		::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO);
216	pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength
217		::max_with_normal_ratio(MAXIMUM_BLOCK_LENGTH, NORMAL_DISPATCH_RATIO);
218	pub const SS58Prefix: u8 = 42;
219}
220
221// Configure FRAME pallets to include in runtime.
222#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)]
223impl frame_system::Config for Runtime {
224	/// Block & extrinsics weights: base values and limits.
225	type BlockWeights = BlockWeights;
226	/// The maximum length of a block (in bytes).
227	type BlockLength = BlockLength;
228	/// The index type for storing how many extrinsics an account has signed.
229	type Nonce = Nonce;
230	/// The type for hashing blocks and tries.
231	type Hash = Hash;
232	/// The hashing algorithm used.
233	type Hashing = Hashing;
234	/// The identifier used to distinguish between accounts.
235	type AccountId = AccountId;
236	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
237	type Lookup = IdentityLookup<AccountId>;
238	/// The block type.
239	type Block = Block;
240	/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
241	type BlockHashCount = BlockHashCount;
242	/// The weight of database operations that the runtime can invoke.
243	type DbWeight = RuntimeDbWeight;
244	/// Version of the runtime.
245	type Version = Version;
246	/// The data to be stored in an account.
247	type AccountData = pallet_balances::AccountData<Balance>;
248	/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
249	type SS58Prefix = SS58Prefix;
250	type MaxConsumers = ConstU32<16>;
251}
252
253impl pallet_aura::Config for Runtime {
254	type AuthorityId = AuraId;
255	type MaxAuthorities = ConstU32<32>;
256	type DisabledValidators = ();
257	type AllowMultipleBlocksPerSlot = ConstBool<false>;
258	type SlotDuration = pallet_aura::MinimumPeriodTimesTwo<Runtime>;
259}
260
261impl pallet_grandpa::Config for Runtime {
262	type RuntimeEvent = RuntimeEvent;
263	type WeightInfo = ();
264	type MaxAuthorities = ConstU32<32>;
265	type MaxNominators = ConstU32<0>;
266	type MaxSetIdSessionEntries = ConstU64<0>;
267	type KeyOwnerProof = sp_core::Void;
268	type EquivocationReportSystem = ();
269}
270
271impl cumulus_pallet_weight_reclaim::Config for Runtime {
272	type WeightInfo = ();
273}
274
275parameter_types! {
276	pub storage EnableManualSeal: bool = false;
277}
278
279pub struct ConsensusOnTimestampSet<T>(PhantomData<T>);
280impl<T: pallet_aura::Config> OnTimestampSet<T::Moment> for ConsensusOnTimestampSet<T> {
281	fn on_timestamp_set(moment: T::Moment) {
282		if EnableManualSeal::get() {
283			return;
284		}
285		<pallet_aura::Pallet<T> as OnTimestampSet<T::Moment>>::on_timestamp_set(moment)
286	}
287}
288
289impl pallet_timestamp::Config for Runtime {
290	type Moment = u64;
291	type OnTimestampSet = ConsensusOnTimestampSet<Self>;
292	type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
293	type WeightInfo = ();
294}
295
296pub const EXISTENTIAL_DEPOSIT: u128 = 0;
297
298impl pallet_balances::Config for Runtime {
299	type RuntimeEvent = RuntimeEvent;
300	type RuntimeHoldReason = RuntimeHoldReason;
301	type RuntimeFreezeReason = RuntimeFreezeReason;
302	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
303	type Balance = Balance;
304	type DustRemoval = ();
305	type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
306	type AccountStore = System;
307	type ReserveIdentifier = [u8; 8];
308	type FreezeIdentifier = RuntimeFreezeReason;
309	type MaxLocks = ConstU32<50>;
310	type MaxReserves = ConstU32<50>;
311	type MaxFreezes = ConstU32<1>;
312	type DoneSlashHandler = ();
313}
314
315impl pallet_transaction_payment::Config for Runtime {
316	type RuntimeEvent = RuntimeEvent;
317	type OnChargeTransaction = FungibleAdapter<Balances, ()>;
318	type WeightToFee = IdentityFee<Balance>;
319	type LengthToFee = IdentityFee<Balance>;
320	/// Parameterized slow adjusting fee updated based on
321	/// <https://research.web3.foundation/Polkadot/overview/token-economics#2-slow-adjusting-mechanism>
322	type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Runtime>;
323	type OperationalFeeMultiplier = ConstU8<5>;
324	type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
325}
326
327impl pallet_sudo::Config for Runtime {
328	type RuntimeEvent = RuntimeEvent;
329	type RuntimeCall = RuntimeCall;
330	type WeightInfo = pallet_sudo::weights::SubstrateWeight<Self>;
331}
332
333impl pallet_evm_chain_id::Config for Runtime {}
334
335pub struct FindAuthorTruncated<F>(PhantomData<F>);
336impl<F: FindAuthor<u32>> FindAuthor<H160> for FindAuthorTruncated<F> {
337	fn find_author<'a, I>(digests: I) -> Option<H160>
338	where
339		I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
340	{
341		if let Some(author_index) = F::find_author(digests) {
342			let authority_id =
343				pallet_aura::Authorities::<Runtime>::get()[author_index as usize].clone();
344			return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
345		}
346		None
347	}
348}
349
350const BLOCK_GAS_LIMIT: u64 = 75_000_000;
351const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
352/// The maximum storage growth per block in bytes.
353const MAX_STORAGE_GROWTH: u64 = 400 * 1024;
354
355parameter_types! {
356	pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
357	pub const GasLimitPovSizeRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_POV_SIZE);
358	pub const GasLimitStorageGrowthRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_STORAGE_GROWTH);
359	pub PrecompilesValue: FrontierPrecompiles<Runtime> = FrontierPrecompiles::<_>::new();
360	pub WeightPerGas: Weight = Weight::from_parts(weight_per_gas(BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK), 0);
361}
362
363impl pallet_evm::Config for Runtime {
364	type AccountProvider = pallet_evm::FrameSystemAccountProvider<Self>;
365	type FeeCalculator = BaseFee;
366	type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
367	type WeightPerGas = WeightPerGas;
368	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
369	type CallOrigin = EnsureAccountId20;
370	type WithdrawOrigin = EnsureAccountId20;
371	type AddressMapping = IdentityAddressMapping;
372	type Currency = Balances;
373	type PrecompilesType = FrontierPrecompiles<Self>;
374	type PrecompilesValue = PrecompilesValue;
375	type ChainId = EVMChainId;
376	type BlockGasLimit = BlockGasLimit;
377	type Runner = pallet_evm::runner::stack::Runner<Self>;
378	type OnChargeTransaction = ();
379	type OnCreate = ();
380	type FindAuthor = FindAuthorTruncated<Aura>;
381	type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
382	type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
383	type Timestamp = Timestamp;
384	type CreateOriginFilter = ();
385	type CreateInnerOriginFilter = ();
386	type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;
387}
388
389parameter_types! {
390	pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes;
391}
392
393impl pallet_ethereum::Config for Runtime {
394	type StateRoot = pallet_ethereum::IntermediateStateRoot<Self::Version>;
395	type PostLogContent = PostBlockAndTxnHashes;
396	type ExtraDataLength = ConstU32<30>;
397}
398
399parameter_types! {
400	pub BoundDivision: U256 = U256::from(1024);
401}
402
403impl pallet_dynamic_fee::Config for Runtime {
404	type MinGasPriceBoundDivisor = BoundDivision;
405}
406
407parameter_types! {
408	pub DefaultBaseFeePerGas: U256 = U256::from(1_000_000_000);
409	pub DefaultElasticity: Permill = Permill::from_parts(125_000);
410}
411pub struct BaseFeeThreshold;
412impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
413	fn lower() -> Permill {
414		Permill::zero()
415	}
416	fn ideal() -> Permill {
417		Permill::from_parts(500_000)
418	}
419	fn upper() -> Permill {
420		Permill::from_parts(1_000_000)
421	}
422}
423impl pallet_base_fee::Config for Runtime {
424	type Threshold = BaseFeeThreshold;
425	type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
426	type DefaultElasticity = DefaultElasticity;
427}
428
429#[frame_support::pallet]
430pub mod pallet_manual_seal {
431	use super::*;
432	use frame_support::pallet_prelude::*;
433
434	#[pallet::pallet]
435	pub struct Pallet<T>(PhantomData<T>);
436
437	#[pallet::config]
438	pub trait Config: frame_system::Config {}
439
440	#[pallet::genesis_config]
441	#[derive(frame_support::DefaultNoBound)]
442	pub struct GenesisConfig<T> {
443		pub enable: bool,
444		#[serde(skip)]
445		pub _config: PhantomData<T>,
446	}
447
448	#[pallet::genesis_build]
449	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
450		fn build(&self) {
451			EnableManualSeal::set(&self.enable);
452		}
453	}
454}
455
456impl pallet_manual_seal::Config for Runtime {}
457
458// Create the runtime by composing the FRAME pallets that were previously configured.
459#[frame_support::runtime]
460mod runtime {
461	#[runtime::runtime]
462	#[runtime::derive(
463		RuntimeEvent,
464		RuntimeCall,
465		RuntimeError,
466		RuntimeOrigin,
467		RuntimeFreezeReason,
468		RuntimeHoldReason,
469		RuntimeSlashReason,
470		RuntimeLockId,
471		RuntimeTask
472	)]
473	pub struct Runtime;
474
475	#[runtime::pallet_index(0)]
476	pub type System = frame_system;
477
478	#[runtime::pallet_index(1)]
479	pub type Timestamp = pallet_timestamp;
480
481	#[runtime::pallet_index(2)]
482	pub type Aura = pallet_aura;
483
484	#[runtime::pallet_index(3)]
485	pub type Grandpa = pallet_grandpa;
486
487	#[runtime::pallet_index(4)]
488	pub type Balances = pallet_balances;
489
490	#[runtime::pallet_index(5)]
491	pub type TransactionPayment = pallet_transaction_payment;
492
493	#[runtime::pallet_index(6)]
494	pub type Sudo = pallet_sudo;
495
496	#[runtime::pallet_index(7)]
497	pub type Ethereum = pallet_ethereum;
498
499	#[runtime::pallet_index(8)]
500	pub type EVM = pallet_evm;
501
502	#[runtime::pallet_index(9)]
503	pub type EVMChainId = pallet_evm_chain_id;
504
505	#[runtime::pallet_index(10)]
506	pub type BaseFee = pallet_base_fee;
507
508	#[runtime::pallet_index(11)]
509	pub type ManualSeal = pallet_manual_seal;
510}
511
512#[derive(Clone)]
513pub struct TransactionConverter<B>(PhantomData<B>);
514
515impl<B> Default for TransactionConverter<B> {
516	fn default() -> Self {
517		Self(PhantomData)
518	}
519}
520
521impl<B: BlockT> fp_rpc::ConvertTransaction<<B as BlockT>::Extrinsic> for TransactionConverter<B> {
522	fn convert_transaction(
523		&self,
524		transaction: pallet_ethereum::Transaction,
525	) -> <B as BlockT>::Extrinsic {
526		let extrinsic = UncheckedExtrinsic::new_bare(
527			pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
528		);
529		let encoded = extrinsic.encode();
530		<B as BlockT>::Extrinsic::decode(&mut &encoded[..])
531			.expect("Encoded extrinsic is always valid")
532	}
533}
534
535impl fp_self_contained::SelfContainedCall for RuntimeCall {
536	type SignedInfo = H160;
537
538	fn is_self_contained(&self) -> bool {
539		match self {
540			RuntimeCall::Ethereum(call) => call.is_self_contained(),
541			_ => false,
542		}
543	}
544
545	fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
546		match self {
547			RuntimeCall::Ethereum(call) => call.check_self_contained(),
548			_ => None,
549		}
550	}
551
552	fn validate_self_contained(
553		&self,
554		info: &Self::SignedInfo,
555		dispatch_info: &DispatchInfoOf<RuntimeCall>,
556		len: usize,
557	) -> Option<TransactionValidity> {
558		match self {
559			RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
560			_ => None,
561		}
562	}
563
564	fn pre_dispatch_self_contained(
565		&self,
566		info: &Self::SignedInfo,
567		dispatch_info: &DispatchInfoOf<RuntimeCall>,
568		len: usize,
569	) -> Option<Result<(), TransactionValidityError>> {
570		match self {
571			RuntimeCall::Ethereum(call) => {
572				call.pre_dispatch_self_contained(info, dispatch_info, len)
573			}
574			_ => None,
575		}
576	}
577
578	fn apply_self_contained(
579		self,
580		info: Self::SignedInfo,
581	) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
582		match self {
583			call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => {
584				Some(call.dispatch(RuntimeOrigin::from(
585					pallet_ethereum::RawOrigin::EthereumTransaction(info),
586				)))
587			}
588			_ => None,
589		}
590	}
591}
592
593#[cfg(feature = "runtime-benchmarks")]
594mod benches {
595	frame_benchmarking::define_benchmarks!(
596		[frame_benchmarking, BaselineBench::<Runtime>]
597		[frame_system, SystemBench::<Runtime>]
598		[pallet_balances, Balances]
599		[pallet_timestamp, Timestamp]
600		[pallet_sudo, Sudo]
601		[pallet_evm, EVM]
602		[pallet_evm_precompile_curve25519, EVMPrecompileCurve25519Bench::<Runtime>]
603		[pallet_evm_precompile_sha3fips, EVMPrecompileSha3FIPSBench::<Runtime>]
604	);
605}
606
607impl_runtime_apis! {
608	impl sp_api::Core<Block> for Runtime {
609		fn version() -> RuntimeVersion {
610			VERSION
611		}
612
613		fn execute_block(block: Block) {
614			Executive::execute_block(block)
615		}
616
617		fn initialize_block(header: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode {
618			Executive::initialize_block(header)
619		}
620	}
621
622	impl sp_api::Metadata<Block> for Runtime {
623		fn metadata() -> OpaqueMetadata {
624			OpaqueMetadata::new(Runtime::metadata().into())
625		}
626
627		fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
628			Runtime::metadata_at_version(version)
629		}
630
631		fn metadata_versions() -> Vec<u32> {
632			Runtime::metadata_versions()
633		}
634	}
635
636	impl sp_block_builder::BlockBuilder<Block> for Runtime {
637		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
638			Executive::apply_extrinsic(extrinsic)
639		}
640
641		fn finalize_block() -> <Block as BlockT>::Header {
642			Executive::finalize_block()
643		}
644
645		fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
646			data.create_extrinsics()
647		}
648
649		fn check_inherents(
650			block: Block,
651			data: sp_inherents::InherentData,
652		) -> sp_inherents::CheckInherentsResult {
653			data.check_extrinsics(&block)
654		}
655	}
656
657	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
658		fn validate_transaction(
659			source: TransactionSource,
660			tx: <Block as BlockT>::Extrinsic,
661			block_hash: <Block as BlockT>::Hash,
662		) -> TransactionValidity {
663			Executive::validate_transaction(source, tx, block_hash)
664		}
665	}
666
667	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
668		fn offchain_worker(header: &<Block as BlockT>::Header) {
669			Executive::offchain_worker(header)
670		}
671	}
672
673	impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
674		fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
675			build_state::<RuntimeGenesisConfig>(config)
676		}
677
678		fn get_preset(id: &Option<PresetId>) -> Option<Vec<u8>> {
679			frame_support::genesis_builder_helper::get_preset::<RuntimeGenesisConfig>(id, genesis_config_preset::get_preset)
680		}
681
682		fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
683			vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
684		}
685	}
686
687	impl sp_session::SessionKeys<Block> for Runtime {
688		fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
689			opaque::SessionKeys::generate(seed)
690		}
691
692		fn decode_session_keys(
693			encoded: Vec<u8>,
694		) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
695			opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
696		}
697	}
698
699	impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
700		fn slot_duration() -> sp_consensus_aura::SlotDuration {
701			sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
702		}
703
704		fn authorities() -> Vec<AuraId> {
705			pallet_aura::Authorities::<Runtime>::get().into_inner()
706		}
707	}
708
709	impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
710		fn grandpa_authorities() -> GrandpaAuthorityList {
711			Grandpa::grandpa_authorities()
712		}
713
714		fn current_set_id() -> sp_consensus_grandpa::SetId {
715			Grandpa::current_set_id()
716		}
717
718		fn submit_report_equivocation_unsigned_extrinsic(
719			_equivocation_proof: sp_consensus_grandpa::EquivocationProof<
720				<Block as BlockT>::Hash,
721				NumberFor<Block>,
722			>,
723			_key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
724		) -> Option<()> {
725			None
726		}
727
728		fn generate_key_ownership_proof(
729			_set_id: sp_consensus_grandpa::SetId,
730			_authority_id: GrandpaId,
731		) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
732			// NOTE: this is the only implementation possible since we've
733			// defined our key owner proof type as a bottom type (i.e. a type
734			// with no values).
735			None
736		}
737	}
738
739	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
740		fn account_nonce(account: AccountId) -> Nonce {
741			System::account_nonce(account)
742		}
743	}
744
745	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
746		Block,
747		Balance,
748	> for Runtime {
749		fn query_info(
750			uxt: <Block as BlockT>::Extrinsic,
751			len: u32
752		) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
753			TransactionPayment::query_info(uxt, len)
754		}
755
756		fn query_fee_details(
757			uxt: <Block as BlockT>::Extrinsic,
758			len: u32,
759		) -> pallet_transaction_payment::FeeDetails<Balance> {
760			TransactionPayment::query_fee_details(uxt, len)
761		}
762
763		fn query_weight_to_fee(weight: Weight) -> Balance {
764			TransactionPayment::weight_to_fee(weight)
765		}
766
767		fn query_length_to_fee(length: u32) -> Balance {
768			TransactionPayment::length_to_fee(length)
769		}
770	}
771
772	impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
773		fn chain_id() -> u64 {
774			<Runtime as pallet_evm::Config>::ChainId::get()
775		}
776
777		fn account_basic(address: H160) -> EVMAccount {
778			let (account, _) = pallet_evm::Pallet::<Runtime>::account_basic(&address);
779			account
780		}
781
782		fn gas_price() -> U256 {
783			let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
784			gas_price
785		}
786
787		fn account_code_at(address: H160) -> Vec<u8> {
788			pallet_evm::AccountCodes::<Runtime>::get(address)
789		}
790
791		fn author() -> H160 {
792			<pallet_evm::Pallet<Runtime>>::find_author()
793		}
794
795		fn storage_at(address: H160, index: U256) -> H256 {
796			pallet_evm::AccountStorages::<Runtime>::get(address, H256::from(index.to_big_endian()))
797		}
798
799		fn call(
800			from: H160,
801			to: H160,
802			data: Vec<u8>,
803			value: U256,
804			gas_limit: U256,
805			max_fee_per_gas: Option<U256>,
806			max_priority_fee_per_gas: Option<U256>,
807			nonce: Option<U256>,
808			estimate: bool,
809			access_list: Option<Vec<(H160, Vec<H256>)>>,
810			authorization_list: Option<AuthorizationList>,
811		) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
812			use pallet_evm::GasWeightMapping as _;
813
814			let config = if estimate {
815				let mut config = <Runtime as pallet_evm::Config>::config().clone();
816				config.estimate = true;
817				Some(config)
818			} else {
819				None
820			};
821
822			// Estimated encoded transaction size must be based on the heaviest transaction
823			// type (EIP7702Transaction) to be compatible with all transaction types.
824			let mut estimated_transaction_len = data.len() +
825				// pallet ethereum index: 1
826				// transact call index: 1
827				// Transaction enum variant: 1
828				// chain_id 8 bytes
829				// nonce: 32
830				// max_priority_fee_per_gas: 32
831				// max_fee_per_gas: 32
832				// gas_limit: 32
833				// action: 21 (enum varianrt + call address)
834				// value: 32
835				// access_list: 1 (empty vec size)
836				// authorization_list: 1 (empty vec size)
837				// 65 bytes signature
838				259;
839
840			if access_list.is_some() {
841				estimated_transaction_len += access_list.encoded_size();
842			}
843
844			if authorization_list.is_some() {
845				estimated_transaction_len += authorization_list.encoded_size();
846			}
847
848			let gas_limit = if gas_limit > U256::from(u64::MAX) {
849				u64::MAX
850			} else {
851				gas_limit.low_u64()
852			};
853			let without_base_extrinsic_weight = true;
854
855			let (weight_limit, proof_size_base_cost) =
856				match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
857					gas_limit,
858					without_base_extrinsic_weight
859				) {
860					weight_limit if weight_limit.proof_size() > 0 => {
861						(Some(weight_limit), Some(estimated_transaction_len as u64))
862					}
863					_ => (None, None),
864				};
865
866			<Runtime as pallet_evm::Config>::Runner::call(
867				from,
868				to,
869				data,
870				value,
871				gas_limit.unique_saturated_into(),
872				max_fee_per_gas,
873				max_priority_fee_per_gas,
874				nonce,
875				access_list.unwrap_or_default(),
876				authorization_list.unwrap_or_default(),
877				false,
878				true,
879				weight_limit,
880				proof_size_base_cost,
881				config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
882			).map_err(|err| err.error.into())
883		}
884
885		fn create(
886			from: H160,
887			data: Vec<u8>,
888			value: U256,
889			gas_limit: U256,
890			max_fee_per_gas: Option<U256>,
891			max_priority_fee_per_gas: Option<U256>,
892			nonce: Option<U256>,
893			estimate: bool,
894			access_list: Option<Vec<(H160, Vec<H256>)>>,
895			authorization_list: Option<AuthorizationList>,
896		) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
897			use pallet_evm::GasWeightMapping as _;
898
899			let config = if estimate {
900				let mut config = <Runtime as pallet_evm::Config>::config().clone();
901				config.estimate = true;
902				Some(config)
903			} else {
904				None
905			};
906
907
908			let mut estimated_transaction_len = data.len() +
909				// from: 20
910				// value: 32
911				// gas_limit: 32
912				// nonce: 32
913				// 1 byte transaction action variant
914				// chain id 8 bytes
915				// 65 bytes signature
916				190;
917
918			if max_fee_per_gas.is_some() {
919				estimated_transaction_len += 32;
920			}
921			if max_priority_fee_per_gas.is_some() {
922				estimated_transaction_len += 32;
923			}
924			if access_list.is_some() {
925				estimated_transaction_len += access_list.encoded_size();
926			}
927			if authorization_list.is_some() {
928				estimated_transaction_len += authorization_list.encoded_size();
929			}
930
931			let gas_limit = if gas_limit > U256::from(u64::MAX) {
932				u64::MAX
933			} else {
934				gas_limit.low_u64()
935			};
936			let without_base_extrinsic_weight = true;
937
938			let (weight_limit, proof_size_base_cost) =
939				match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
940					gas_limit,
941					without_base_extrinsic_weight
942				) {
943					weight_limit if weight_limit.proof_size() > 0 => {
944						(Some(weight_limit), Some(estimated_transaction_len as u64))
945					}
946					_ => (None, None),
947				};
948
949			<Runtime as pallet_evm::Config>::Runner::create(
950				from,
951				data,
952				value,
953				gas_limit.unique_saturated_into(),
954				max_fee_per_gas,
955				max_priority_fee_per_gas,
956				nonce,
957				access_list.unwrap_or_default(),
958				authorization_list.unwrap_or_default(),
959				false,
960				true,
961				weight_limit,
962				proof_size_base_cost,
963				config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
964			).map_err(|err| err.error.into())
965		}
966
967		fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
968			pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
969		}
970
971		fn current_block() -> Option<pallet_ethereum::Block> {
972			pallet_ethereum::CurrentBlock::<Runtime>::get()
973		}
974
975		fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
976			pallet_ethereum::CurrentReceipts::<Runtime>::get()
977		}
978
979		fn current_all() -> (
980			Option<pallet_ethereum::Block>,
981			Option<Vec<pallet_ethereum::Receipt>>,
982			Option<Vec<TransactionStatus>>
983		) {
984			(
985				pallet_ethereum::CurrentBlock::<Runtime>::get(),
986				pallet_ethereum::CurrentReceipts::<Runtime>::get(),
987				pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
988			)
989		}
990
991		fn extrinsic_filter(
992			xts: Vec<<Block as BlockT>::Extrinsic>,
993		) -> Vec<EthereumTransaction> {
994			xts.into_iter().filter_map(|xt| match xt.0.function {
995				RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
996				_ => None
997			}).collect::<Vec<EthereumTransaction>>()
998		}
999
1000		fn elasticity() -> Option<Permill> {
1001			Some(pallet_base_fee::Elasticity::<Runtime>::get())
1002		}
1003
1004		fn gas_limit_multiplier_support() {}
1005
1006		fn pending_block(
1007			xts: Vec<<Block as BlockT>::Extrinsic>,
1008		) -> (Option<pallet_ethereum::Block>, Option<Vec<TransactionStatus>>) {
1009			for ext in xts.into_iter() {
1010				let _ = Executive::apply_extrinsic(ext);
1011			}
1012
1013			Ethereum::on_finalize(System::block_number() + 1);
1014
1015			(
1016				pallet_ethereum::CurrentBlock::<Runtime>::get(),
1017				pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
1018			)
1019		}
1020
1021		fn initialize_pending_block(header: &<Block as BlockT>::Header) {
1022			Executive::initialize_block(header);
1023		}
1024	}
1025
1026	impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
1027		fn convert_transaction(transaction: EthereumTransaction) -> <Block as BlockT>::Extrinsic {
1028			UncheckedExtrinsic::new_bare(
1029				pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
1030			)
1031		}
1032	}
1033
1034	#[cfg(feature = "runtime-benchmarks")]
1035	impl frame_benchmarking::Benchmark<Block> for Runtime {
1036		fn benchmark_metadata(extra: bool) -> (
1037			Vec<frame_benchmarking::BenchmarkList>,
1038			Vec<frame_support::traits::StorageInfo>,
1039		) {
1040			use frame_benchmarking::{baseline, BenchmarkList};
1041			use frame_support::traits::StorageInfoTrait;
1042
1043			use baseline::Pallet as BaselineBench;
1044			use frame_system_benchmarking::Pallet as SystemBench;
1045
1046			use pallet_evm_precompile_curve25519_benchmarking::Pallet as EVMPrecompileCurve25519Bench;
1047			use pallet_evm_precompile_sha3fips_benchmarking::Pallet as EVMPrecompileSha3FIPSBench;
1048
1049			let mut list = Vec::<BenchmarkList>::new();
1050			list_benchmarks!(list, extra);
1051
1052			let storage_info = AllPalletsWithSystem::storage_info();
1053			(list, storage_info)
1054		}
1055
1056		#[allow(non_local_definitions)]
1057		fn dispatch_benchmark(
1058			config: frame_benchmarking::BenchmarkConfig
1059		) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
1060			use frame_benchmarking::{baseline, BenchmarkBatch};
1061			use frame_support::traits::TrackedStorageKey;
1062
1063			use baseline::Pallet as BaselineBench;
1064			use frame_system_benchmarking::Pallet as SystemBench;
1065			use pallet_evm_precompile_curve25519_benchmarking::Pallet as EVMPrecompileCurve25519Bench;
1066			use pallet_evm_precompile_sha3fips_benchmarking::Pallet as EVMPrecompileSha3FIPSBench;
1067
1068			impl baseline::Config for Runtime {}
1069			impl frame_system_benchmarking::Config for Runtime {}
1070			impl pallet_evm_precompile_curve25519_benchmarking::Config for Runtime {}
1071			impl pallet_evm_precompile_sha3fips_benchmarking::Config for Runtime {}
1072
1073			let whitelist: Vec<TrackedStorageKey> = Vec::new();
1074
1075			let mut batches = Vec::<BenchmarkBatch>::new();
1076			let params = (&config, &whitelist);
1077			add_benchmarks!(params, batches);
1078			Ok(batches)
1079		}
1080	}
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085	use super::{Runtime, WeightPerGas};
1086	#[test]
1087	fn configured_base_extrinsic_weight_is_evm_compatible() {
1088		let min_ethereum_transaction_weight = WeightPerGas::get() * 21_000;
1089		let base_extrinsic = <Runtime as frame_system::Config>::BlockWeights::get()
1090			.get(frame_support::dispatch::DispatchClass::Normal)
1091			.base_extrinsic;
1092		assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time());
1093	}
1094}