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]
18
macro_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
19
		fn replay_on_idle() {
30
			use frame_system::pallet_prelude::BlockNumberFor;
31
			use frame_support::traits::OnIdle;
32

            
33
19
			let weight = <frame_system::Pallet<Runtime>>::block_weight();
34
19
			let max_weight = <
35
19
					<Runtime as frame_system::Config>::BlockWeights as
36
19
					frame_support::traits::Get<_>
37
19
				>::get().max_block;
38
19
			let remaining_weight = max_weight.saturating_sub(weight.total());
39
19
			if remaining_weight.all_gt(Weight::zero()) {
40
19
				let _ = <AllPalletsWithSystem as OnIdle<BlockNumberFor<Runtime>>>::on_idle(
41
19
					<frame_system::Pallet<Runtime>>::block_number(),
42
19
					remaining_weight,
43
19
				);
44
19
			}
45
19
		}
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
19
				fn trace_transaction(
163
19
					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
164
19
					traced_transaction: &EthereumTransaction,
165
19
					header: &<Block as BlockT>::Header,
166
19
				) -> Result<
167
19
					(),
168
19
					sp_runtime::DispatchError,
169
19
				> {
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
19
						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
19
							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
38
							for ext in extrinsics.into_iter() {
192
38
								let _ = match &ext.0.function {
193
19
									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
19
										frame_system::BlockWeight::<Runtime>::kill();
200

            
201
19
										if transaction == traced_transaction {
202
19
											EvmTracer::new().trace(|| Executive::apply_extrinsic(ext));
203
19
											return Ok(());
204
										} else {
205
											Executive::apply_extrinsic(ext)
206
										}
207
									}
208
19
									_ => Executive::apply_extrinsic(ext),
209
								};
210

            
211
19
								if let Some(EthereumTracingStatus::TransactionExited) = EthereumTracer::status() {
212
									return Ok(());
213
19
								}
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
19
						})
232
					}
233
					#[cfg(not(feature = "evm-tracing"))]
234
					Err(sp_runtime::DispatchError::Other(
235
						"Missing `evm-tracing` compile time feature flag.",
236
					))
237
19
				}
238

            
239
19
				fn trace_block(
240
19
					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
241
19
					known_transactions: Vec<H256>,
242
19
					header: &<Block as BlockT>::Header,
243
19
				) -> Result<
244
19
					(),
245
19
					sp_runtime::DispatchError,
246
19
				> {
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
19
						EthereumTracer::block(|| {
258
19
							let mut config = <Runtime as pallet_evm::Config>::config().clone();
259
19
							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
19
							Executive::initialize_block(header);
267

            
268
							// Apply all extrinsics. Ethereum extrinsics are traced.
269
76
							for ext in extrinsics.into_iter() {
270
76
								match &ext.0.function {
271
38
									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
38
										frame_system::BlockWeight::<Runtime>::kill();
279

            
280
38
										let tx_hash = &transaction.hash();
281
38
										if known_transactions.contains(&tx_hash) {
282
											// Each known extrinsic is a new call stack.
283
38
											EvmTracer::emit_new();
284
38
											EvmTracer::new().trace(|| {
285
38
												if let Err(err) = Executive::apply_extrinsic(ext) {
286
38
													log::debug!(
287
														target: "tracing",
288
														"Could not trace eth transaction (hash: {}): {:?}",
289
														&tx_hash,
290
														err
291
													);
292
												}
293
38
											});
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
38
										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
38
										}
313
									}
314
								};
315
							}
316

            
317
							// Replay on_idle
318
							// Some XCM messages with eth-xcm transaction might be executed at on_idle
319
19
							replay_on_idle();
320

            
321
19
							Ok(())
322
19
						})
323
					}
324
					#[cfg(not(feature = "evm-tracing"))]
325
					Err(sp_runtime::DispatchError::Other(
326
						"Missing `evm-tracing` compile time feature flag.",
327
					))
328
19
				}
329

            
330
19
				fn trace_call(
331
19
					header: &<Block as BlockT>::Header,
332
19
					from: H160,
333
19
					to: H160,
334
19
					data: Vec<u8>,
335
19
					value: U256,
336
19
					gas_limit: U256,
337
19
					max_fee_per_gas: Option<U256>,
338
19
					max_priority_fee_per_gas: Option<U256>,
339
19
					nonce: Option<U256>,
340
19
					access_list: Option<Vec<(H160, Vec<H256>)>>,
341
19
					authorization_list: Option<AuthorizationList>,
342
19
				) -> 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
19
						Executive::initialize_block(header);
350

            
351
19
						EvmTracer::new().trace(|| {
352
19
							let is_transactional = false;
353
19
							let validate = true;
354

            
355
19
							let transaction_data = pallet_ethereum::TransactionData::new(
356
19
								pallet_ethereum::TransactionAction::Call(to),
357
19
								data.clone(),
358
19
								nonce.unwrap_or_default(),
359
19
								gas_limit,
360
19
								None,
361
19
								max_fee_per_gas.or(Some(U256::default())),
362
19
								max_priority_fee_per_gas.or(Some(U256::default())),
363
19
								value,
364
19
								Some(<Runtime as pallet_evm::Config>::ChainId::get()),
365
19
								access_list.clone().unwrap_or_default(),
366
19
								authorization_list.clone().unwrap_or_default(),
367
							);
368

            
369
19
							let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
370

            
371
19
							let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
372

            
373
19
							let _ = <Runtime as pallet_evm::Config>::Runner::call(
374
19
								from,
375
19
								to,
376
19
								data,
377
19
								value,
378
19
								gas_limit,
379
19
								max_fee_per_gas,
380
19
								max_priority_fee_per_gas,
381
19
								nonce,
382
19
								access_list.unwrap_or_default(),
383
19
								authorization_list.unwrap_or_default(),
384
19
								is_transactional,
385
19
								validate,
386
19
								weight_limit,
387
19
								proof_size_base_cost,
388
19
								<Runtime as pallet_evm::Config>::config(),
389
19
							);
390
19
						});
391
19
						Ok(())
392
					}
393
					#[cfg(not(feature = "evm-tracing"))]
394
					Err(sp_runtime::DispatchError::Other(
395
						"Missing `evm-tracing` compile time feature flag.",
396
					))
397
19
				}
398
			}
399

            
400
			impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block> for Runtime {
401
19
				fn extrinsic_filter(
402
19
					xts_ready: Vec<<Block as BlockT>::Extrinsic>,
403
19
					xts_future: Vec<<Block as BlockT>::Extrinsic>,
404
19
				) -> TxPoolResponse {
405
					TxPoolResponse {
406
19
						ready: xts_ready
407
19
							.into_iter()
408
38
							.filter_map(|xt| match xt.0.function {
409
19
								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
410
19
								_ => None,
411
38
							})
412
19
							.collect(),
413
19
						future: xts_future
414
19
							.into_iter()
415
38
							.filter_map(|xt| match xt.0.function {
416
19
								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
417
19
								_ => None,
418
38
							})
419
19
							.collect(),
420
					}
421
19
				}
422
			}
423

            
424
			impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
425
19
				fn chain_id() -> u64 {
426
19
					<Runtime as pallet_evm::Config>::ChainId::get()
427
19
				}
428

            
429
19
				fn account_basic(address: H160) -> EVMAccount {
430
19
					let (account, _) = EVM::account_basic(&address);
431
19
					account
432
19
				}
433

            
434
19
				fn gas_price() -> U256 {
435
19
					let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
436
19
					gas_price
437
19
				}
438

            
439
19
				fn account_code_at(address: H160) -> Vec<u8> {
440
19
					pallet_evm::AccountCodes::<Runtime>::get(address)
441
19
				}
442

            
443
19
				fn author() -> H160 {
444
19
					<pallet_evm::Pallet<Runtime>>::find_author()
445
19
				}
446

            
447
19
				fn storage_at(address: H160, index: U256) -> H256 {
448
19
					let tmp: [u8; 32] = index.to_big_endian();
449
19
					pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
450
19
				}
451

            
452
19
				fn call(
453
19
					from: H160,
454
19
					to: H160,
455
19
					data: Vec<u8>,
456
19
					value: U256,
457
19
					gas_limit: U256,
458
19
					max_fee_per_gas: Option<U256>,
459
19
					max_priority_fee_per_gas: Option<U256>,
460
19
					nonce: Option<U256>,
461
19
					estimate: bool,
462
19
					access_list: Option<Vec<(H160, Vec<H256>)>>,
463
19
					authorization_list: Option<AuthorizationList>,
464
19
				) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
465
19
					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
19
						None
471
					};
472
19
					let is_transactional = false;
473
19
					let validate = true;
474

            
475
19
					let transaction_data = pallet_ethereum::TransactionData::new(
476
19
						pallet_ethereum::TransactionAction::Call(to),
477
19
						data.clone(),
478
19
						nonce.unwrap_or_default(),
479
19
						gas_limit,
480
19
						None,
481
19
						max_fee_per_gas.or(Some(U256::default())),
482
19
						max_priority_fee_per_gas.or(Some(U256::default())),
483
19
						value,
484
19
						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
485
19
						access_list.clone().unwrap_or_default(),
486
19
						authorization_list.clone().unwrap_or_default(),
487
					);
488

            
489
19
					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
490

            
491
19
					let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
492

            
493
19
					<Runtime as pallet_evm::Config>::Runner::call(
494
19
						from,
495
19
						to,
496
19
						data,
497
19
						value,
498
19
						gas_limit,
499
19
						max_fee_per_gas,
500
19
						max_priority_fee_per_gas,
501
19
						nonce,
502
19
						access_list.unwrap_or_default(),
503
19
						authorization_list.unwrap_or_default(),
504
19
						is_transactional,
505
19
						validate,
506
19
						weight_limit,
507
19
						proof_size_base_cost,
508
19
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
509
19
					).map_err(|err| err.error.into())
510
19
				}
511

            
512
19
				fn create(
513
19
					from: H160,
514
19
					data: Vec<u8>,
515
19
					value: U256,
516
19
					gas_limit: U256,
517
19
					max_fee_per_gas: Option<U256>,
518
19
					max_priority_fee_per_gas: Option<U256>,
519
19
					nonce: Option<U256>,
520
19
					estimate: bool,
521
19
					access_list: Option<Vec<(H160, Vec<H256>)>>,
522
19
					authorization_list: Option<AuthorizationList>,
523
19
				) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
524
19
					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
19
						None
530
					};
531
19
					let is_transactional = false;
532
19
					let validate = true;
533

            
534
19
					let transaction_data = pallet_ethereum::TransactionData::new(
535
19
						pallet_ethereum::TransactionAction::Create,
536
19
						data.clone(),
537
19
						nonce.unwrap_or_default(),
538
19
						gas_limit,
539
19
						None,
540
19
						max_fee_per_gas.or(Some(U256::default())),
541
19
						max_priority_fee_per_gas.or(Some(U256::default())),
542
19
						value,
543
19
						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
544
19
						access_list.clone().unwrap_or_default(),
545
19
						authorization_list.clone().unwrap_or_default(),
546
					);
547

            
548
19
					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
549

            
550
19
					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
19
					<Runtime as pallet_evm::Config>::Runner::create(
554
19
						from,
555
19
						data,
556
19
						value,
557
19
						gas_limit,
558
19
						max_fee_per_gas,
559
19
						max_priority_fee_per_gas,
560
19
						nonce,
561
19
						access_list.unwrap_or_default(),
562
19
						authorization_list.unwrap_or_default(),
563
19
						is_transactional,
564
19
						validate,
565
19
						weight_limit,
566
19
						proof_size_base_cost,
567
19
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
568
19
					).map_err(|err| err.error.into())
569
19
				}
570

            
571
19
				fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
572
19
					pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
573
19
				}
574

            
575
19
				fn current_block() -> Option<pallet_ethereum::Block> {
576
19
					pallet_ethereum::CurrentBlock::<Runtime>::get()
577
19
				}
578

            
579
19
				fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
580
19
					pallet_ethereum::CurrentReceipts::<Runtime>::get()
581
19
				}
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
57
				fn can_author(
671
57
					author: nimbus_primitives::NimbusId,
672
57
					slot: u32,
673
57
					parent_header: &<Block as BlockT>::Header
674
57
				) -> bool {
675
					use pallet_parachain_staking::Config as PalletParachainStakingConfig;
676

            
677
57
					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
57
					System::initialize(
684
57
						&block_number,
685
57
						&parent_header.hash(),
686
57
						&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
57
					if pallet_parachain_staking::Pallet::<Self>::round()
693
57
						.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
57
						AuthorInherent::can_author(&author, &slot)
719
					}
720
57
				}
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),
									fun: Fungible(fungibles_amount * i as u128),
								}
								.into()
							})
							.chain(
								core::iter::once(
									Asset {
										id: AssetId(Location::parent()),
										fun: Fungible(u128::MAX)
									}
								)
							)
							.collect::<Vec<_>>();
							for (i, asset) in assets.iter().enumerate() {
								if let Asset {
									id: AssetId(location),
									fun: Fungible(_)
								} = asset {
									EvmForeignAssets::set_asset(
										location.clone(),
										i as u128
									);
									XcmWeightTrader::set_asset_price(
										location.clone(),
										1u128.pow(18)
									);
								}
							}
							assets.into()
						}
					}
					impl pallet_xcm_benchmarks::generic::Config for Runtime {
						type RuntimeCall = RuntimeCall;
						type TransactAsset = Balances;
						fn worst_case_response() -> (u64, Response) {
							(0u64, Response::Version(Default::default()))
						}
						fn worst_case_asset_exchange()
							-> Result<(XcmAssets, XcmAssets), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
						fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
						fn export_message_origin_and_destination()
							-> Result<(Location, NetworkId, Junctions), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
						fn transact_origin_and_runtime_call()
							-> Result<(Location, RuntimeCall), BenchmarkError> {
							Ok((Location::parent(), frame_system::Call::remark_with_event {
								remark: vec![]
							}.into()))
						}
						fn subscribe_origin() -> Result<Location, BenchmarkError> {
							Ok(Location::parent())
						}
						fn claimable_asset()
							-> Result<(Location, Location, XcmAssets), BenchmarkError> {
							let origin = Location::parent();
							let assets: XcmAssets = (AssetId(Location::parent()), 1_000u128)
								.into();
							let ticket = Location { parents: 0, interior: [].into() /* Here */ };
							Ok((origin, ticket, assets))
						}
						fn worst_case_for_trader() -> Result<(Asset, WeightLimit), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
						fn unlockable_asset()
							-> Result<(Location, Location, Asset), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
						fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
							Err(BenchmarkError::Skip)
						}
					}
					$($bench_custom)*
					let whitelist: Vec<TrackedStorageKey> = vec![
						// Block Number
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"02a5c1b19ab7a04f536c519aca4983ac")
							.to_vec().into(),
						// Total Issuance
						hex_literal::hex!(  "c2261276cc9d1f8598ea4b6a74b15c2f"
											"57c875e4cff74148e4628f264b974c80")
							.to_vec().into(),
						// Execution Phase
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"ff553b5a9862a516939d82b3d3d8661a")
							.to_vec().into(),
						// Event Count
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"0a98fdbe9ce6c55837576c60c7af3850")
							.to_vec().into(),
						// System Events
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"80d41e5e16056765bc8461851072c9d7")
							.to_vec().into(),
						// System BlockWeight
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"34abf5cb34d6244378cddbf18e849d96")
							.to_vec().into(),
						// ParachainStaking Round
						hex_literal::hex!(  "a686a3043d0adcf2fa655e57bc595a78"
											"13792e785168f725b60e2969c7fc2552")
							.to_vec().into(),
						// Treasury Account (py/trsry)
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"b99d880ec681799c0cf30e8886371da9"
											"7be2919ac397ba499ea5e57132180ec6"
											"6d6f646c70792f747273727900000000"
											"00000000"
						).to_vec().into(),
						// Treasury Account (pc/trsry)
						hex_literal::hex!(  "26aa394eea5630e07c48ae0c9558cef7"
											"b99d880ec681799c0cf30e8886371da9"
											"7be2919ac397ba499ea5e57132180ec6"
											"6d6f646c70632f747273727900000000"
											"00000000"
						).to_vec().into(),
						// ParachainInfo ParachainId
						hex_literal::hex!(  "0d715f2646c8f85767b5d2764bb27826"
											"04a74d81251e398fd8a0a4d55023bb3f")
							.to_vec().into(),
						// Parameters Parameters
						hex_literal::hex!(  "c63bdd4a39095ccf55623a6f2872bf8a" // Pallet: "Parameters"
											"c63bdd4a39095ccf55623a6f2872bf8a" // Storage Prefix: "Parameters"
											// MoonbaseRuntimeRuntimeParamsRuntimeParametersKey(FeesTreasuryProportion)
											"71d0aacb690b61280d0c97c6b6a666640000"
										)
							.to_vec().into(),
					];
					let mut batches = Vec::<BenchmarkBatch>::new();
					let params = (&config, &whitelist);
					add_benchmarks!(params, batches);
					if batches.is_empty() {
						return Err("Benchmark not found for this pallet.".into());
					}
					Ok(batches)
				}
			}
			#[cfg(feature = "try-runtime")]
			impl frame_try_runtime::TryRuntime<Block> for Runtime {
				fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
					log::info!("try-runtime::on_runtime_upgrade()");
					// NOTE: intentional expect: we don't want to propagate the error backwards,
					// and want to have a backtrace here. If any of the pre/post migration checks
					// fail, we shall stop right here and right now.
					let weight = Executive::try_runtime_upgrade(checks)
						.expect("runtime upgrade logic *must* be infallible");
					(weight, RuntimeBlockWeights::get().max_block)
				}
				fn execute_block(
					block: Block,
					state_root_check: bool,
					signature_check: bool,
					select: frame_try_runtime::TryStateSelect
				) -> Weight {
					log::info!(
						"try-runtime: executing block {:?} / root checks: {:?} / try-state-select: {:?}",
						block.header.hash(),
						state_root_check,
						select,
					);
					// NOTE: intentional unwrap: we don't want to propagate the error backwards,
					// and want to have a backtrace here.
					Executive::try_execute_block(
						block,
						state_root_check,
						signature_check,
						select,
					).expect("execute-block failed")
				}
			}
965411
		}
	};
}