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