moonbeam_runtime_common/
apis.rs

1// Copyright 2019-2025 PureStake Inc.
2// This file is part of Moonbeam.
3
4// Moonbeam is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Moonbeam is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16
17#[macro_export]
18macro_rules! impl_runtime_apis_plus_common {
19    ({$($custom:tt)*} {$($bench_custom:tt)*}) => {
20    	use ethereum::AuthorizationList;
21
22		#[cfg(feature = "evm-tracing")]
23		// Helper function to replay the "on_idle" hook for all pallets, we need this for
24		// evm-tracing because some ethereum-xcm transactions might be executed at on_idle.
25		//
26		// We need to make sure that we replay on_idle exactly the same way as the
27		// original block execution, but unfortunatly frame executive diosn't provide a function
28		// to replay only on_idle, so we need to copy here some code inside frame executive.
29		fn replay_on_idle() {
30			use frame_system::pallet_prelude::BlockNumberFor;
31			use frame_support::traits::OnIdle;
32
33			let weight = <frame_system::Pallet<Runtime>>::block_weight();
34			let max_weight = <
35					<Runtime as frame_system::Config>::BlockWeights as
36					frame_support::traits::Get<_>
37				>::get().max_block;
38			let remaining_weight = max_weight.saturating_sub(weight.total());
39			if remaining_weight.all_gt(Weight::zero()) {
40				let _ = <AllPalletsWithSystem as OnIdle<BlockNumberFor<Runtime>>>::on_idle(
41					<frame_system::Pallet<Runtime>>::block_number(),
42					remaining_weight,
43				);
44			}
45		}
46
47		impl_runtime_apis! {
48			$($custom)*
49
50			impl sp_api::Core<Block> for Runtime {
51				fn version() -> RuntimeVersion {
52					VERSION
53				}
54
55				fn execute_block(block: Block) {
56					Executive::execute_block(block)
57				}
58
59				fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
60					Executive::initialize_block(header)
61				}
62			}
63
64			impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
65				fn relay_parent_offset() -> u32 {
66					crate::RELAY_PARENT_OFFSET
67				}
68			}
69
70			impl cumulus_primitives_core::GetCoreSelectorApi<Block> for Runtime {
71				fn core_selector() -> (cumulus_primitives_core::CoreSelector, cumulus_primitives_core::ClaimQueueOffset) {
72					ParachainSystem::core_selector()
73				}
74			}
75
76			impl sp_api::Metadata<Block> for Runtime {
77				fn metadata() -> OpaqueMetadata {
78					OpaqueMetadata::new(Runtime::metadata().into())
79				}
80
81				fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
82					Runtime::metadata_at_version(version)
83				}
84
85				fn metadata_versions() -> Vec<u32> {
86					Runtime::metadata_versions()
87				}
88			}
89
90			impl sp_block_builder::BlockBuilder<Block> for Runtime {
91				fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
92					Executive::apply_extrinsic(extrinsic)
93				}
94
95				fn finalize_block() -> <Block as BlockT>::Header {
96					Executive::finalize_block()
97				}
98
99				fn inherent_extrinsics(
100					data: sp_inherents::InherentData,
101				) -> Vec<<Block as BlockT>::Extrinsic> {
102					data.create_extrinsics()
103				}
104
105				fn check_inherents(
106					block: Block,
107					data: sp_inherents::InherentData,
108				) -> sp_inherents::CheckInherentsResult {
109					data.check_extrinsics(&block)
110				}
111			}
112
113			impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
114				fn offchain_worker(header: &<Block as BlockT>::Header) {
115					Executive::offchain_worker(header)
116				}
117			}
118
119			impl sp_session::SessionKeys<Block> for Runtime {
120				fn decode_session_keys(
121					encoded: Vec<u8>,
122				) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
123					opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
124				}
125
126				fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
127					opaque::SessionKeys::generate(seed)
128				}
129			}
130
131			impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
132				fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
133					frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(config)
134				}
135
136				#[cfg(not(feature = "disable-genesis-builder"))]
137				fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
138					frame_support::genesis_builder_helper::get_preset::<RuntimeGenesisConfig>(id, genesis_config_preset::get_preset)
139				}
140				#[cfg(feature = "disable-genesis-builder")]
141				fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
142					None
143				}
144
145				#[cfg(not(feature = "disable-genesis-builder"))]
146				fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
147					genesis_config_preset::preset_names()
148				}
149				#[cfg(feature = "disable-genesis-builder")]
150				fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
151					Default::default()
152				}
153			}
154
155			impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
156				fn account_nonce(account: AccountId) -> Index {
157					System::account_nonce(account)
158				}
159			}
160
161			impl moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block> for Runtime {
162				fn trace_transaction(
163					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
164					traced_transaction: &EthereumTransaction,
165					header: &<Block as BlockT>::Header,
166				) -> Result<
167					(),
168					sp_runtime::DispatchError,
169				> {
170					#[cfg(feature = "evm-tracing")]
171					{
172						use moonbeam_evm_tracer::tracer::{
173							EthereumTracingStatus,
174							EvmTracer,
175							EthereumTracer
176						};
177						use frame_support::storage::unhashed;
178						use frame_system::pallet_prelude::BlockNumberFor;
179
180						// Tell the CallDispatcher we are tracing a specific Transaction.
181						EthereumTracer::transaction(traced_transaction.hash(), || {
182							// Initialize block: calls the "on_initialize" hook on every pallet
183							// in AllPalletsWithSystem.
184							// After pallet message queue was introduced, this must be done only after
185							// enabling XCM tracing by calling ETHEREUM_TRACING_STATUS::using
186							// in the storage
187							Executive::initialize_block(header);
188
189							// Apply the a subset of extrinsics: all the substrate-specific or ethereum
190							// transactions that preceded the requested transaction.
191							for ext in extrinsics.into_iter() {
192								let _ = match &ext.0.function {
193									RuntimeCall::Ethereum(transact { transaction }) => {
194										// Reset the previously consumed weight when tracing ethereum transactions.
195										// This is necessary because EVM tracing introduces additional
196										// (ref_time) overhead, which differs from the production runtime behavior.
197										// Without resetting the block weight, the extra tracing overhead could
198										// leading to some transactions to incorrectly fail during tracing.
199										frame_system::BlockWeight::<Runtime>::kill();
200
201										if transaction == traced_transaction {
202											EvmTracer::new().trace(|| Executive::apply_extrinsic(ext));
203											return Ok(());
204										} else {
205											Executive::apply_extrinsic(ext)
206										}
207									}
208									_ => Executive::apply_extrinsic(ext),
209								};
210
211								if let Some(EthereumTracingStatus::TransactionExited) = EthereumTracer::status() {
212									return Ok(());
213								}
214							}
215
216							if let Some(EthereumTracingStatus::Transaction(_)) = EthereumTracer::status() {
217								// If the transaction was not found, it might be
218								// an eth-xcm transaction that was executed at on_idle
219								replay_on_idle();
220							}
221
222							if let Some(EthereumTracingStatus::TransactionExited) = EthereumTracer::status() {
223								// The transaction was found
224								Ok(())
225							} else {
226								// The transaction was not-found
227								Err(sp_runtime::DispatchError::Other(
228									"Failed to find Ethereum transaction among the extrinsics.",
229								))
230							}
231						})
232					}
233					#[cfg(not(feature = "evm-tracing"))]
234					Err(sp_runtime::DispatchError::Other(
235						"Missing `evm-tracing` compile time feature flag.",
236					))
237				}
238
239				fn trace_block(
240					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
241					known_transactions: Vec<H256>,
242					header: &<Block as BlockT>::Header,
243				) -> Result<
244					(),
245					sp_runtime::DispatchError,
246				> {
247					#[cfg(feature = "evm-tracing")]
248					{
249						use moonbeam_evm_tracer::tracer::{
250							EthereumTracingStatus,
251							EvmTracer,
252							EthereumTracer
253						};
254						use frame_system::pallet_prelude::BlockNumberFor;
255
256						// Tell the CallDispatcher we are tracing a full Block.
257						EthereumTracer::block(|| {
258							let mut config = <Runtime as pallet_evm::Config>::config().clone();
259							config.estimate = true;
260
261							// Initialize block: calls the "on_initialize" hook on every pallet
262							// in AllPalletsWithSystem.
263							// After pallet message queue was introduced, this must be done only after
264							// enabling XCM tracing by calling ETHEREUM_TRACING_STATUS::using
265							// in the storage
266							Executive::initialize_block(header);
267
268							// Apply all extrinsics. Ethereum extrinsics are traced.
269							for ext in extrinsics.into_iter() {
270								match &ext.0.function {
271									RuntimeCall::Ethereum(transact { transaction }) => {
272
273										// Reset the previously consumed weight when tracing multiple transactions.
274										// This is necessary because EVM tracing introduces additional
275										// (ref_time) overhead, which differs from the production runtime behavior.
276										// Without resetting the block weight, the extra tracing overhead could
277										// leading to some transactions to incorrectly fail during tracing.
278										frame_system::BlockWeight::<Runtime>::kill();
279
280										let tx_hash = &transaction.hash();
281										if known_transactions.contains(&tx_hash) {
282											// Each known extrinsic is a new call stack.
283											EvmTracer::emit_new();
284											EvmTracer::new().trace(|| {
285												if let Err(err) = Executive::apply_extrinsic(ext) {
286													log::debug!(
287														target: "tracing",
288														"Could not trace eth transaction (hash: {}): {:?}",
289														&tx_hash,
290														err
291													);
292												}
293											});
294										} else {
295											if let Err(err) = Executive::apply_extrinsic(ext) {
296												log::debug!(
297													target: "tracing",
298													"Failed to apply eth extrinsic (hash: {}): {:?}",
299													&tx_hash,
300													err
301												);
302											}
303										}
304									}
305									_ => {
306										if let Err(err) = Executive::apply_extrinsic(ext) {
307											log::debug!(
308												target: "tracing",
309												"Failed to apply non-eth extrinsic: {:?}",
310												err
311											);
312										}
313									}
314								};
315							}
316
317							// Replay on_idle
318							// Some XCM messages with eth-xcm transaction might be executed at on_idle
319							replay_on_idle();
320
321							Ok(())
322						})
323					}
324					#[cfg(not(feature = "evm-tracing"))]
325					Err(sp_runtime::DispatchError::Other(
326						"Missing `evm-tracing` compile time feature flag.",
327					))
328				}
329
330				fn trace_call(
331					header: &<Block as BlockT>::Header,
332					from: H160,
333					to: H160,
334					data: Vec<u8>,
335					value: U256,
336					gas_limit: U256,
337					max_fee_per_gas: Option<U256>,
338					max_priority_fee_per_gas: Option<U256>,
339					nonce: Option<U256>,
340					access_list: Option<Vec<(H160, Vec<H256>)>>,
341					authorization_list: Option<AuthorizationList>,
342				) -> Result<(), sp_runtime::DispatchError> {
343					#[cfg(feature = "evm-tracing")]
344					{
345						use moonbeam_evm_tracer::tracer::EvmTracer;
346
347						// Initialize block: calls the "on_initialize" hook on every pallet
348						// in AllPalletsWithSystem.
349						Executive::initialize_block(header);
350
351						EvmTracer::new().trace(|| {
352							let is_transactional = false;
353							let validate = true;
354
355							let transaction_data = pallet_ethereum::TransactionData::new(
356								pallet_ethereum::TransactionAction::Call(to),
357								data.clone(),
358								nonce.unwrap_or_default(),
359								gas_limit,
360								None,
361								max_fee_per_gas.or(Some(U256::default())),
362								max_priority_fee_per_gas.or(Some(U256::default())),
363								value,
364								Some(<Runtime as pallet_evm::Config>::ChainId::get()),
365								access_list.clone().unwrap_or_default(),
366								authorization_list.clone().unwrap_or_default(),
367							);
368
369							let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
370
371							let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
372
373							let _ = <Runtime as pallet_evm::Config>::Runner::call(
374								from,
375								to,
376								data,
377								value,
378								gas_limit,
379								max_fee_per_gas,
380								max_priority_fee_per_gas,
381								nonce,
382								access_list.unwrap_or_default(),
383								authorization_list.unwrap_or_default(),
384								is_transactional,
385								validate,
386								weight_limit,
387								proof_size_base_cost,
388								<Runtime as pallet_evm::Config>::config(),
389							);
390						});
391						Ok(())
392					}
393					#[cfg(not(feature = "evm-tracing"))]
394					Err(sp_runtime::DispatchError::Other(
395						"Missing `evm-tracing` compile time feature flag.",
396					))
397				}
398			}
399
400			impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block> for Runtime {
401				fn extrinsic_filter(
402					xts_ready: Vec<<Block as BlockT>::Extrinsic>,
403					xts_future: Vec<<Block as BlockT>::Extrinsic>,
404				) -> TxPoolResponse {
405					TxPoolResponse {
406						ready: xts_ready
407							.into_iter()
408							.filter_map(|xt| match xt.0.function {
409								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
410								_ => None,
411							})
412							.collect(),
413						future: xts_future
414							.into_iter()
415							.filter_map(|xt| match xt.0.function {
416								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
417								_ => None,
418							})
419							.collect(),
420					}
421				}
422			}
423
424			impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
425				fn chain_id() -> u64 {
426					<Runtime as pallet_evm::Config>::ChainId::get()
427				}
428
429				fn account_basic(address: H160) -> EVMAccount {
430					let (account, _) = EVM::account_basic(&address);
431					account
432				}
433
434				fn gas_price() -> U256 {
435					let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
436					gas_price
437				}
438
439				fn account_code_at(address: H160) -> Vec<u8> {
440					pallet_evm::AccountCodes::<Runtime>::get(address)
441				}
442
443				fn author() -> H160 {
444					<pallet_evm::Pallet<Runtime>>::find_author()
445				}
446
447				fn storage_at(address: H160, index: U256) -> H256 {
448					let tmp: [u8; 32] = index.to_big_endian();
449					pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
450				}
451
452				fn call(
453					from: H160,
454					to: H160,
455					data: Vec<u8>,
456					value: U256,
457					gas_limit: U256,
458					max_fee_per_gas: Option<U256>,
459					max_priority_fee_per_gas: Option<U256>,
460					nonce: Option<U256>,
461					estimate: bool,
462					access_list: Option<Vec<(H160, Vec<H256>)>>,
463					authorization_list: Option<AuthorizationList>,
464				) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
465					let config = if estimate {
466						let mut config = <Runtime as pallet_evm::Config>::config().clone();
467						config.estimate = true;
468						Some(config)
469					} else {
470						None
471					};
472					let is_transactional = false;
473					let validate = true;
474
475					let transaction_data = pallet_ethereum::TransactionData::new(
476						pallet_ethereum::TransactionAction::Call(to),
477						data.clone(),
478						nonce.unwrap_or_default(),
479						gas_limit,
480						None,
481						max_fee_per_gas.or(Some(U256::default())),
482						max_priority_fee_per_gas.or(Some(U256::default())),
483						value,
484						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
485						access_list.clone().unwrap_or_default(),
486						authorization_list.clone().unwrap_or_default(),
487					);
488
489					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
490
491					let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
492
493					<Runtime as pallet_evm::Config>::Runner::call(
494						from,
495						to,
496						data,
497						value,
498						gas_limit,
499						max_fee_per_gas,
500						max_priority_fee_per_gas,
501						nonce,
502						access_list.unwrap_or_default(),
503						authorization_list.unwrap_or_default(),
504						is_transactional,
505						validate,
506						weight_limit,
507						proof_size_base_cost,
508						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
509					).map_err(|err| err.error.into())
510				}
511
512				fn create(
513					from: H160,
514					data: Vec<u8>,
515					value: U256,
516					gas_limit: U256,
517					max_fee_per_gas: Option<U256>,
518					max_priority_fee_per_gas: Option<U256>,
519					nonce: Option<U256>,
520					estimate: bool,
521					access_list: Option<Vec<(H160, Vec<H256>)>>,
522					authorization_list: Option<AuthorizationList>,
523				) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
524					let config = if estimate {
525						let mut config = <Runtime as pallet_evm::Config>::config().clone();
526						config.estimate = true;
527						Some(config)
528					} else {
529						None
530					};
531					let is_transactional = false;
532					let validate = true;
533
534					let transaction_data = pallet_ethereum::TransactionData::new(
535						pallet_ethereum::TransactionAction::Create,
536						data.clone(),
537						nonce.unwrap_or_default(),
538						gas_limit,
539						None,
540						max_fee_per_gas.or(Some(U256::default())),
541						max_priority_fee_per_gas.or(Some(U256::default())),
542						value,
543						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
544						access_list.clone().unwrap_or_default(),
545						authorization_list.clone().unwrap_or_default(),
546					);
547
548					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
549
550					let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
551
552					#[allow(clippy::or_fun_call)] // suggestion not helpful here
553					<Runtime as pallet_evm::Config>::Runner::create(
554						from,
555						data,
556						value,
557						gas_limit,
558						max_fee_per_gas,
559						max_priority_fee_per_gas,
560						nonce,
561						access_list.unwrap_or_default(),
562						authorization_list.unwrap_or_default(),
563						is_transactional,
564						validate,
565						weight_limit,
566						proof_size_base_cost,
567						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
568					).map_err(|err| err.error.into())
569				}
570
571				fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
572					pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
573				}
574
575				fn current_block() -> Option<pallet_ethereum::Block> {
576					pallet_ethereum::CurrentBlock::<Runtime>::get()
577				}
578
579				fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
580					pallet_ethereum::CurrentReceipts::<Runtime>::get()
581				}
582
583				fn current_all() -> (
584					Option<pallet_ethereum::Block>,
585					Option<Vec<pallet_ethereum::Receipt>>,
586					Option<Vec<TransactionStatus>>,
587				) {
588					(
589						pallet_ethereum::CurrentBlock::<Runtime>::get(),
590						pallet_ethereum::CurrentReceipts::<Runtime>::get(),
591						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get(),
592					)
593				}
594
595				fn extrinsic_filter(
596					xts: Vec<<Block as BlockT>::Extrinsic>,
597				) -> Vec<EthereumTransaction> {
598					xts.into_iter().filter_map(|xt| match xt.0.function {
599						RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
600						_ => None
601					}).collect::<Vec<EthereumTransaction>>()
602				}
603
604				fn elasticity() -> Option<Permill> {
605					None
606				}
607
608				fn gas_limit_multiplier_support() {}
609
610				fn pending_block(
611					xts: Vec<<Block as sp_runtime::traits::Block>::Extrinsic>
612				) -> (
613					Option<pallet_ethereum::Block>, Option<sp_std::prelude::Vec<TransactionStatus>>
614				) {
615					for ext in xts.into_iter() {
616						let _ = Executive::apply_extrinsic(ext);
617					}
618
619					Ethereum::on_finalize(System::block_number() + 1);
620
621					(
622						pallet_ethereum::CurrentBlock::<Runtime>::get(),
623						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
624					)
625				 }
626
627				fn initialize_pending_block(header: &<Block as BlockT>::Header) {
628					pallet_randomness::vrf::using_fake_vrf(|| {
629						let _ = Executive::initialize_block(header);
630					})
631				}
632			}
633
634			impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
635				fn convert_transaction(
636					transaction: pallet_ethereum::Transaction
637				) -> <Block as BlockT>::Extrinsic {
638					UncheckedExtrinsic::new_bare(
639						pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
640					)
641				}
642			}
643
644			impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
645			for Runtime {
646				fn query_info(
647					uxt: <Block as BlockT>::Extrinsic,
648					len: u32,
649				) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
650					TransactionPayment::query_info(uxt, len)
651				}
652
653				fn query_fee_details(
654					uxt: <Block as BlockT>::Extrinsic,
655					len: u32,
656				) -> pallet_transaction_payment::FeeDetails<Balance> {
657					TransactionPayment::query_fee_details(uxt, len)
658				}
659
660				fn query_weight_to_fee(weight: Weight) -> Balance {
661					TransactionPayment::weight_to_fee(weight)
662				}
663
664				fn query_length_to_fee(length: u32) -> Balance {
665					TransactionPayment::length_to_fee(length)
666				}
667			}
668
669			impl nimbus_primitives::NimbusApi<Block> for Runtime {
670				fn can_author(
671					author: nimbus_primitives::NimbusId,
672					slot: u32,
673					parent_header: &<Block as BlockT>::Header
674				) -> bool {
675					use pallet_parachain_staking::Config as PalletParachainStakingConfig;
676
677					let block_number = parent_header.number + 1;
678
679					// The Moonbeam runtimes use an entropy source that needs to do some accounting
680					// work during block initialization. Therefore we initialize it here to match
681					// the state it will be in when the next block is being executed.
682					use frame_support::traits::OnInitialize;
683					System::initialize(
684						&block_number,
685						&parent_header.hash(),
686						&parent_header.digest,
687					);
688
689					// Because the staking solution calculates the next staking set at the beginning
690					// of the first block in the new round, the only way to accurately predict the
691					// authors is to compute the selection during prediction.
692					if pallet_parachain_staking::Pallet::<Self>::round()
693						.should_update(block_number) {
694						// get author account id
695						use nimbus_primitives::AccountLookup;
696						let author_account_id = if let Some(account) =
697							pallet_author_mapping::Pallet::<Self>::lookup_account(&author) {
698							account
699						} else {
700							// return false if author mapping not registered like in can_author impl
701							return false
702						};
703						let candidates = pallet_parachain_staking::Pallet::<Self>::compute_top_candidates();
704						if candidates.is_empty() {
705							// If there are zero selected candidates, we use the same eligibility
706							// as the previous round
707							return AuthorInherent::can_author(&author, &slot);
708						}
709
710						// predict eligibility post-selection by computing selection results now
711						let (eligible, _) =
712							pallet_author_slot_filter::compute_pseudo_random_subset::<Self>(
713								candidates,
714								&slot
715							);
716						eligible.contains(&author_account_id)
717					} else {
718						AuthorInherent::can_author(&author, &slot)
719					}
720				}
721			}
722
723			impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
724				fn collect_collation_info(
725					header: &<Block as BlockT>::Header
726				) -> cumulus_primitives_core::CollationInfo {
727					ParachainSystem::collect_collation_info(header)
728				}
729			}
730
731			impl session_keys_primitives::VrfApi<Block> for Runtime {
732				fn get_last_vrf_output() -> Option<<Block as BlockT>::Hash> {
733					// TODO: remove in future runtime upgrade along with storage item
734					if pallet_randomness::Pallet::<Self>::not_first_block().is_none() {
735						return None;
736					}
737					pallet_randomness::Pallet::<Self>::local_vrf_output()
738				}
739				fn vrf_key_lookup(
740					nimbus_id: nimbus_primitives::NimbusId
741				) -> Option<session_keys_primitives::VrfId> {
742					use session_keys_primitives::KeysLookup;
743					AuthorMapping::lookup_keys(&nimbus_id)
744				}
745			}
746
747			impl xcm_runtime_apis::fees::XcmPaymentApi<Block> for Runtime {
748				fn query_acceptable_payment_assets(
749					xcm_version: xcm::Version
750				) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
751					XcmWeightTrader::query_acceptable_payment_assets(xcm_version)
752				}
753
754				fn query_weight_to_asset_fee(
755					weight: Weight, asset: VersionedAssetId
756				) -> Result<u128, XcmPaymentApiError> {
757					XcmWeightTrader::query_weight_to_asset_fee(weight, asset)
758				}
759
760				fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
761					PolkadotXcm::query_xcm_weight(message)
762				}
763
764				fn query_delivery_fees(
765					destination: VersionedLocation, message: VersionedXcm<()>
766				) -> Result<VersionedAssets, XcmPaymentApiError> {
767					PolkadotXcm::query_delivery_fees(destination, message)
768				}
769			}
770
771			impl xcm_runtime_apis::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller>
772				for Runtime {
773					fn dry_run_call(
774						origin: OriginCaller,
775						call: RuntimeCall,
776						result_xcms_version: XcmVersion
777					) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
778						PolkadotXcm::dry_run_call::<
779							Runtime,
780							xcm_config::XcmRouter,
781							OriginCaller,
782							RuntimeCall>(origin, call, result_xcms_version)
783					}
784
785					fn dry_run_xcm(
786						origin_location: VersionedLocation,
787						xcm: VersionedXcm<RuntimeCall>
788					) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
789						PolkadotXcm::dry_run_xcm::<xcm_config::XcmRouter>(origin_location, xcm)
790					}
791				}
792
793			impl xcm_runtime_apis::conversions::LocationToAccountApi<Block, AccountId> for Runtime {
794				fn convert_location(location: VersionedLocation) -> Result<
795					AccountId,
796					xcm_runtime_apis::conversions::Error
797				> {
798					xcm_runtime_apis::conversions::LocationToAccountHelper::<
799						AccountId,
800						xcm_config::LocationToAccountId,
801					>::convert_location(location)
802				}
803			}
804
805			#[cfg(feature = "runtime-benchmarks")]
806			impl frame_benchmarking::Benchmark<Block> for Runtime {
807
808				fn benchmark_metadata(extra: bool) -> (
809					Vec<frame_benchmarking::BenchmarkList>,
810					Vec<frame_support::traits::StorageInfo>,
811				) {
812					use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
813					use frame_system_benchmarking::Pallet as SystemBench;
814					use frame_support::traits::StorageInfoTrait;
815
816					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
817					use pallet_transaction_payment::benchmarking::Pallet as TransactionPaymentBenchmark;
818
819					let mut list = Vec::<BenchmarkList>::new();
820					list_benchmarks!(list, extra);
821
822					let storage_info = AllPalletsWithSystem::storage_info();
823
824					return (list, storage_info)
825				}
826
827				#[allow(non_local_definitions)]
828				fn dispatch_benchmark(
829					config: frame_benchmarking::BenchmarkConfig,
830				) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
831					use frame_benchmarking::{add_benchmark, BenchmarkBatch, Benchmarking};
832					use frame_support::traits::TrackedStorageKey;
833					use cumulus_primitives_core::ParaId;
834
835					use xcm::latest::prelude::{
836						GeneralIndex, Junction, Junctions, Location, Response, NetworkId, AssetId,
837						Assets as XcmAssets, Fungible, Asset, ParentThen, Parachain, Parent, WeightLimit
838					};
839					use xcm_config::SelfReserve;
840					use frame_benchmarking::BenchmarkError;
841
842					use frame_system_benchmarking::Pallet as SystemBench;
843					// Needed to run `set_code` and `apply_authorized_upgrade` frame_system benchmarks
844					// https://github.com/paritytech/cumulus/pull/2766
845					impl frame_system_benchmarking::Config for Runtime {
846						fn setup_set_code_requirements(code: &Vec<u8>) -> Result<(), BenchmarkError> {
847							ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
848							Ok(())
849						}
850
851						fn verify_set_code() {
852							System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
853						}
854					}
855
856					// Needed to run `charge_transaction_payment` benchmark which distributes
857					// fees to block author. Moonbeam requires an author to be set for fee distribution.
858					use pallet_transaction_payment::benchmarking::Pallet as TransactionPaymentBenchmark;
859					impl pallet_transaction_payment::benchmarking::Config for Runtime {
860						fn setup_benchmark_environment() {
861							// Set a dummy author for the block so fee distribution doesn't panic
862							let author: AccountId = frame_benchmarking::whitelisted_caller();
863							pallet_author_inherent::Author::<Runtime>::put(author);
864						}
865					}
866
867					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
868					parameter_types! {
869						pub const RandomParaId: ParaId = ParaId::new(43211234);
870					}
871
872					/// Custom delivery helper for Moonbeam that works with H160 accounts.
873					/// This is needed because Moonbeam uses AccountKey20 (H160) accounts
874					/// instead of AccountId32, and the standard ToParentDeliveryHelper
875					/// fails when trying to deposit assets to an origin location.
876					pub struct TestDeliveryHelper;
877					impl xcm_builder::EnsureDelivery for TestDeliveryHelper {
878						fn ensure_successful_delivery(
879							origin_ref: &Location,
880							dest: &Location,
881							_fee_reason: xcm_executor::traits::FeeReason,
882						) -> (Option<xcm_executor::FeesMode>, Option<XcmAssets>) {
883							use xcm_executor::traits::ConvertLocation;
884
885							// Ensure the XCM sender is properly configured for benchmarks
886							// This sets up the HostConfiguration for sending messages
887							<xcm_config::XcmRouter as xcm::latest::SendXcm>::ensure_successful_delivery(Some(dest.clone()));
888
889							// Open HRMP channel for sibling parachain destinations
890							if let Some(Parachain(para_id)) = dest.interior().first() {
891								ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
892									(*para_id).into()
893								);
894							}
895
896							// Deposit existential deposit to the origin account if we can convert it
897							if let Some(account) = xcm_config::LocationToH160::convert_location(origin_ref) {
898								let balance = ExistentialDeposit::get() * 1000u128;
899								let _ = <Balances as frame_support::traits::Currency<_>>::
900									make_free_balance_be(&account.into(), balance);
901							}
902
903							(None, None)
904						}
905					}
906
907					impl pallet_xcm::benchmarking::Config for Runtime {
908				        type DeliveryHelper = TestDeliveryHelper;
909
910						fn get_asset() -> Asset {
911							Asset {
912								id: AssetId(SelfReserve::get()),
913								fun: Fungible(ExistentialDeposit::get()),
914							}
915						}
916
917						fn reachable_dest() -> Option<Location> {
918							Some(Parent.into())
919						}
920
921						fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
922							None
923						}
924
925						fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
926							use xcm_config::SelfReserve;
927
928							ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
929								RandomParaId::get().into()
930							);
931
932							Some((
933								Asset {
934									fun: Fungible(ExistentialDeposit::get()),
935									id: AssetId(SelfReserve::get().into())
936								},
937								// Moonbeam can reserve transfer native token to
938								// some random parachain.
939								ParentThen(Parachain(RandomParaId::get().into()).into()).into(),
940							))
941						}
942
943						fn set_up_complex_asset_transfer(
944						) -> Option<(XcmAssets, u32, Location, Box<dyn FnOnce()>)> {
945							use xcm_config::SelfReserve;
946
947							let destination: xcm::v5::Location = Parent.into();
948
949							let fee_amount: u128 = <Runtime as pallet_balances::Config>::ExistentialDeposit::get();
950							let fee_asset: Asset = (SelfReserve::get(), fee_amount).into();
951
952							// Give some multiple of transferred amount
953							let balance = fee_amount * 1000;
954							let who = frame_benchmarking::whitelisted_caller();
955							let _ =
956								<Balances as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
957
958							// verify initial balance
959							assert_eq!(Balances::free_balance(&who), balance);
960
961							// set up foreign asset
962							let asset_amount: u128 = 10u128;
963							let initial_asset_amount: u128 = asset_amount * 10;
964
965							let asset_id = pallet_moonbeam_foreign_assets::default_asset_id::<Runtime>() + 1;
966							let (_, location, _) = pallet_moonbeam_foreign_assets::create_default_minted_foreign_asset::<Runtime>(
967								asset_id,
968								initial_asset_amount,
969							);
970							let transfer_asset: Asset = (AssetId(location), asset_amount).into();
971
972							let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into();
973							let fee_index: u32 = 0;
974
975							let verify: Box<dyn FnOnce()> = Box::new(move || {
976								// verify balance after transfer, decreased by
977								// transferred amount (and delivery fees)
978								assert!(Balances::free_balance(&who) <= balance - fee_amount);
979							});
980
981							Some((assets, fee_index, destination, verify))
982						}
983					}
984
985					impl pallet_xcm_benchmarks::Config for Runtime {
986						type XcmConfig = xcm_config::XcmExecutorConfig;
987						type AccountIdConverter = xcm_config::LocationToAccountId;
988						type DeliveryHelper = TestDeliveryHelper;
989						fn valid_destination() -> Result<Location, BenchmarkError> {
990							Ok(Location::parent())
991						}
992						fn worst_case_holding(_depositable_count: u32) -> XcmAssets {
993						// 100 fungibles
994							const HOLDING_FUNGIBLES: u32 = 100;
995							let fungibles_amount: u128 = 100;
996							let assets = (0..HOLDING_FUNGIBLES).map(|i| {
997								let location: Location = GeneralIndex(i as u128).into();
998								Asset {
999									id: AssetId(location),
1000									fun: Fungible(fungibles_amount * i as u128),
1001								}
1002								.into()
1003							})
1004							.chain(
1005								core::iter::once(
1006									Asset {
1007										id: AssetId(Location::parent()),
1008										fun: Fungible(u128::MAX)
1009									}
1010								)
1011							)
1012							.collect::<Vec<_>>();
1013
1014
1015							for (i, asset) in assets.iter().enumerate() {
1016								if let Asset {
1017									id: AssetId(location),
1018									fun: Fungible(_)
1019								} = asset {
1020									EvmForeignAssets::set_asset(
1021										location.clone(),
1022										i as u128
1023									);
1024									XcmWeightTrader::set_asset_price(
1025										location.clone(),
1026										1u128.pow(18)
1027									);
1028								}
1029							}
1030							assets.into()
1031						}
1032					}
1033
1034					impl pallet_xcm_benchmarks::generic::Config for Runtime {
1035						type RuntimeCall = RuntimeCall;
1036						type TransactAsset = Balances;
1037
1038						fn worst_case_response() -> (u64, Response) {
1039							(0u64, Response::Version(Default::default()))
1040						}
1041
1042						fn worst_case_asset_exchange()
1043							-> Result<(XcmAssets, XcmAssets), BenchmarkError> {
1044							Err(BenchmarkError::Skip)
1045						}
1046
1047						fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
1048							Err(BenchmarkError::Skip)
1049						}
1050
1051						fn export_message_origin_and_destination()
1052							-> Result<(Location, NetworkId, Junctions), BenchmarkError> {
1053							Err(BenchmarkError::Skip)
1054						}
1055
1056						fn transact_origin_and_runtime_call()
1057							-> Result<(Location, RuntimeCall), BenchmarkError> {
1058							Ok((Location::parent(), frame_system::Call::remark_with_event {
1059								remark: vec![]
1060							}.into()))
1061						}
1062
1063						fn subscribe_origin() -> Result<Location, BenchmarkError> {
1064							Ok(Location::parent())
1065						}
1066
1067						fn claimable_asset()
1068							-> Result<(Location, Location, XcmAssets), BenchmarkError> {
1069							let origin = Location::parent();
1070							let assets: XcmAssets = (AssetId(Location::parent()), 1_000u128)
1071								.into();
1072							let ticket = Location { parents: 0, interior: [].into() /* Here */ };
1073							Ok((origin, ticket, assets))
1074						}
1075
1076						fn worst_case_for_trader() -> Result<(Asset, WeightLimit), BenchmarkError> {
1077							Err(BenchmarkError::Skip)
1078						}
1079
1080						fn unlockable_asset()
1081							-> Result<(Location, Location, Asset), BenchmarkError> {
1082							Err(BenchmarkError::Skip)
1083						}
1084
1085						fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
1086							Err(BenchmarkError::Skip)
1087						}
1088					}
1089
1090					$($bench_custom)*
1091
1092					let whitelist: Vec<TrackedStorageKey> = vec![
1093						// Block Number
1094						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1095											"02a5c1b19ab7a04f536c519aca4983ac")
1096							.to_vec().into(),
1097						// Total Issuance
1098						hex_literal::hex!(  "c2261276cc9d1f8598ea4b6a74b15c2f"
1099											"57c875e4cff74148e4628f264b974c80")
1100							.to_vec().into(),
1101						// Execution Phase
1102						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1103											"ff553b5a9862a516939d82b3d3d8661a")
1104							.to_vec().into(),
1105						// Event Count
1106						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1107											"0a98fdbe9ce6c55837576c60c7af3850")
1108							.to_vec().into(),
1109						// System Events
1110						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1111											"80d41e5e16056765bc8461851072c9d7")
1112							.to_vec().into(),
1113						// System BlockWeight
1114						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1115											"34abf5cb34d6244378cddbf18e849d96")
1116							.to_vec().into(),
1117						// ParachainStaking Round
1118						hex_literal::hex!(  "a686a3043d0adcf2fa655e57bc595a78"
1119											"13792e785168f725b60e2969c7fc2552")
1120							.to_vec().into(),
1121						// Treasury Account (py/trsry)
1122						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1123											"b99d880ec681799c0cf30e8886371da9"
1124											"7be2919ac397ba499ea5e57132180ec6"
1125											"6d6f646c70792f747273727900000000"
1126											"00000000"
1127						).to_vec().into(),
1128						// Treasury Account (pc/trsry)
1129						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
1130											"b99d880ec681799c0cf30e8886371da9"
1131											"7be2919ac397ba499ea5e57132180ec6"
1132											"6d6f646c70632f747273727900000000"
1133											"00000000"
1134						).to_vec().into(),
1135						// ParachainInfo ParachainId
1136						hex_literal::hex!(  "0d715f2646c8f85767b5d2764bb27826"
1137											"04a74d81251e398fd8a0a4d55023bb3f")
1138							.to_vec().into(),
1139						// Parameters Parameters
1140						hex_literal::hex!(  "c63bdd4a39095ccf55623a6f2872bf8a" // Pallet: "Parameters"
1141											"c63bdd4a39095ccf55623a6f2872bf8a" // Storage Prefix: "Parameters"
1142											// MoonbaseRuntimeRuntimeParamsRuntimeParametersKey(FeesTreasuryProportion)
1143											"71d0aacb690b61280d0c97c6b6a666640000"
1144										)
1145							.to_vec().into(),
1146
1147					];
1148
1149					let mut batches = Vec::<BenchmarkBatch>::new();
1150					let params = (&config, &whitelist);
1151
1152					add_benchmarks!(params, batches);
1153
1154					if batches.is_empty() {
1155						return Err("Benchmark not found for this pallet.".into());
1156					}
1157					Ok(batches)
1158				}
1159			}
1160
1161			#[cfg(feature = "try-runtime")]
1162			impl frame_try_runtime::TryRuntime<Block> for Runtime {
1163				fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
1164					log::info!("try-runtime::on_runtime_upgrade()");
1165					// NOTE: intentional expect: we don't want to propagate the error backwards,
1166					// and want to have a backtrace here. If any of the pre/post migration checks
1167					// fail, we shall stop right here and right now.
1168					let weight = Executive::try_runtime_upgrade(checks)
1169						.expect("runtime upgrade logic *must* be infallible");
1170					(weight, RuntimeBlockWeights::get().max_block)
1171				}
1172
1173				fn execute_block(
1174					block: Block,
1175					state_root_check: bool,
1176					signature_check: bool,
1177					select: frame_try_runtime::TryStateSelect
1178				) -> Weight {
1179					log::info!(
1180						"try-runtime: executing block {:?} / root checks: {:?} / try-state-select: {:?}",
1181						block.header.hash(),
1182						state_root_check,
1183						select,
1184					);
1185					// NOTE: intentional unwrap: we don't want to propagate the error backwards,
1186					// and want to have a backtrace here.
1187					Executive::try_execute_block(
1188						block,
1189						state_root_check,
1190						signature_check,
1191						select,
1192					).expect("execute-block failed")
1193				}
1194			}
1195		}
1196	};
1197}