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)*} => {
20

            
21
		#[cfg(feature = "evm-tracing")]
22
		// Helper function to replay the "on_idle" hook for all pallets, we need this for
23
		// evm-tracing because some ethereum-xcm transactions might be executed at on_idle.
24
		//
25
		// We need to make sure that we replay on_idle exactly the same way as the
26
		// original block execution, but unfortunatly frame executive diosn't provide a function
27
		// to replay only on_idle, so we need to copy here some code inside frame executive.
28
22
		fn replay_on_idle() {
29
22
			use frame_system::pallet_prelude::BlockNumberFor;
30
22
			use frame_support::traits::OnIdle;
31
22

            
32
22
			let weight = <frame_system::Pallet<Runtime>>::block_weight();
33
22
			let max_weight = <
34
22
					<Runtime as frame_system::Config>::BlockWeights as
35
22
					frame_support::traits::Get<_>
36
22
				>::get().max_block;
37
22
			let remaining_weight = max_weight.saturating_sub(weight.total());
38
22
			if remaining_weight.all_gt(Weight::zero()) {
39
22
				let _ = <AllPalletsWithSystem as OnIdle<BlockNumberFor<Runtime>>>::on_idle(
40
22
					<frame_system::Pallet<Runtime>>::block_number(),
41
22
					remaining_weight,
42
22
				);
43
22
			}
44
22
		}
45
22

            
46
22
		impl_runtime_apis! {
47
			$($custom)*
48

            
49
			impl sp_api::Core<Block> for Runtime {
50
				fn version() -> RuntimeVersion {
51
					VERSION
52
				}
53

            
54
				fn execute_block(block: Block) {
55
					Executive::execute_block(block)
56
				}
57

            
58
				fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
59
					Executive::initialize_block(header)
60
				}
61
			}
62

            
63
			impl sp_api::Metadata<Block> for Runtime {
64
				fn metadata() -> OpaqueMetadata {
65
					OpaqueMetadata::new(Runtime::metadata().into())
66
				}
67

            
68
				fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
69
					Runtime::metadata_at_version(version)
70
				}
71

            
72
				fn metadata_versions() -> Vec<u32> {
73
					Runtime::metadata_versions()
74
				}
75
			}
76

            
77
			impl sp_block_builder::BlockBuilder<Block> for Runtime {
78
				fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
79
					Executive::apply_extrinsic(extrinsic)
80
				}
81

            
82
				fn finalize_block() -> <Block as BlockT>::Header {
83
					Executive::finalize_block()
84
				}
85

            
86
				fn inherent_extrinsics(
87
					data: sp_inherents::InherentData,
88
				) -> Vec<<Block as BlockT>::Extrinsic> {
89
					data.create_extrinsics()
90
				}
91

            
92
				fn check_inherents(
93
					block: Block,
94
					data: sp_inherents::InherentData,
95
				) -> sp_inherents::CheckInherentsResult {
96
					data.check_extrinsics(&block)
97
				}
98
			}
99

            
100
			impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
101
				fn offchain_worker(header: &<Block as BlockT>::Header) {
102
					Executive::offchain_worker(header)
103
				}
104
			}
105

            
106
			impl sp_session::SessionKeys<Block> for Runtime {
107
				fn decode_session_keys(
108
					encoded: Vec<u8>,
109
				) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
110
					opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
111
				}
112

            
113
				fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
114
					opaque::SessionKeys::generate(seed)
115
				}
116
			}
117

            
118
			#[cfg(not(feature = "disable-genesis-builder"))]
119
			impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
120
				fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
121
					frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(config)
122
				}
123

            
124
				fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
125
					frame_support::genesis_builder_helper::get_preset::<RuntimeGenesisConfig>(id, genesis_config_preset::get_preset)
126
				}
127

            
128
				fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
129
					genesis_config_preset::preset_names()
130
				}
131
			}
132

            
133
			impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
134
				fn account_nonce(account: AccountId) -> Index {
135
					System::account_nonce(account)
136
				}
137
			}
138

            
139
			impl moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block> for Runtime {
140
22
				fn trace_transaction(
141
22
					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
142
22
					traced_transaction: &EthereumTransaction,
143
22
					header: &<Block as BlockT>::Header,
144
22
				) -> Result<
145
22
					(),
146
22
					sp_runtime::DispatchError,
147
22
				> {
148
22
					#[cfg(feature = "evm-tracing")]
149
22
					{
150
22
						use moonbeam_evm_tracer::tracer::EvmTracer;
151
22
						use xcm_primitives::{
152
22
							ETHEREUM_XCM_TRACING_STORAGE_KEY,
153
22
							EthereumXcmTracingStatus
154
22
						};
155
22
						use frame_support::storage::unhashed;
156
22
						use frame_system::pallet_prelude::BlockNumberFor;
157
22

            
158
22
						// Tell the CallDispatcher we are tracing a specific Transaction.
159
22
						unhashed::put::<EthereumXcmTracingStatus>(
160
22
							ETHEREUM_XCM_TRACING_STORAGE_KEY,
161
22
							&EthereumXcmTracingStatus::Transaction(traced_transaction.hash()),
162
22
						);
163
22

            
164
22
						// Initialize block: calls the "on_initialize" hook on every pallet
165
22
						// in AllPalletsWithSystem.
166
22
						// After pallet message queue was introduced, this must be done only after
167
22
						// enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY
168
22
						// in the storage
169
22
						Executive::initialize_block(header);
170

            
171
						// Apply the a subset of extrinsics: all the substrate-specific or ethereum
172
						// transactions that preceded the requested transaction.
173
44
						for ext in extrinsics.into_iter() {
174
22
							let _ = match &ext.0.function {
175
22
								RuntimeCall::Ethereum(transact { transaction }) => {
176
22

            
177
22
									// Reset the previously consumed weight when tracing ethereum transactions.
178
22
									// This is necessary because EVM tracing introduces additional
179
22
									// (ref_time) overhead, which differs from the production runtime behavior.
180
22
									// Without resetting the block weight, the extra tracing overhead could
181
22
									// leading to some transactions to incorrectly fail during tracing.
182
22
									frame_system::BlockWeight::<Runtime>::kill();
183
22

            
184
22
									if transaction == traced_transaction {
185
22
										EvmTracer::new().trace(|| Executive::apply_extrinsic(ext));
186
22
										return Ok(());
187
									} else {
188
										Executive::apply_extrinsic(ext)
189
									}
190
								}
191
22
								_ => Executive::apply_extrinsic(ext),
192
							};
193
22
							if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get(
194
22
								ETHEREUM_XCM_TRACING_STORAGE_KEY
195
22
							) {
196
								return Ok(());
197
							}
198
						}
199

            
200
						if let Some(EthereumXcmTracingStatus::Transaction(_)) = unhashed::get(
201
							ETHEREUM_XCM_TRACING_STORAGE_KEY
202
						) {
203
							// If the transaction was not found, it might be
204
							// an eth-xcm transaction that was executed at on_idle
205
							replay_on_idle();
206
						}
207

            
208
						if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get(
209
							ETHEREUM_XCM_TRACING_STORAGE_KEY
210
						) {
211
							// The transaction was found
212
							Ok(())
213
						} else {
214
							// The transaction was not-found
215
							Err(sp_runtime::DispatchError::Other(
216
								"Failed to find Ethereum transaction among the extrinsics.",
217
							))
218
						}
219
					}
220
					#[cfg(not(feature = "evm-tracing"))]
221
					Err(sp_runtime::DispatchError::Other(
222
						"Missing `evm-tracing` compile time feature flag.",
223
					))
224
				}
225

            
226
22
				fn trace_block(
227
22
					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
228
22
					known_transactions: Vec<H256>,
229
22
					header: &<Block as BlockT>::Header,
230
22
				) -> Result<
231
22
					(),
232
22
					sp_runtime::DispatchError,
233
22
				> {
234
22
					#[cfg(feature = "evm-tracing")]
235
22
					{
236
22
						use moonbeam_evm_tracer::tracer::EvmTracer;
237
22
						use frame_system::pallet_prelude::BlockNumberFor;
238
22
						use xcm_primitives::EthereumXcmTracingStatus;
239
22

            
240
22
						// Tell the CallDispatcher we are tracing a full Block.
241
22
						frame_support::storage::unhashed::put::<EthereumXcmTracingStatus>(
242
22
							xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY,
243
22
							&EthereumXcmTracingStatus::Block,
244
22
						);
245
22

            
246
22
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
247
22
						config.estimate = true;
248
22

            
249
22
						// Initialize block: calls the "on_initialize" hook on every pallet
250
22
						// in AllPalletsWithSystem.
251
22
						// After pallet message queue was introduced, this must be done only after
252
22
						// enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY
253
22
						// in the storage
254
22
						Executive::initialize_block(header);
255

            
256
						// Apply all extrinsics. Ethereum extrinsics are traced.
257
88
						for ext in extrinsics.into_iter() {
258
44
							match &ext.0.function {
259
44
								RuntimeCall::Ethereum(transact { transaction }) => {
260
44

            
261
44
									// Reset the previously consumed weight when tracing multiple transactions.
262
44
									// This is necessary because EVM tracing introduces additional
263
44
									// (ref_time) overhead, which differs from the production runtime behavior.
264
44
									// Without resetting the block weight, the extra tracing overhead could
265
44
									// leading to some transactions to incorrectly fail during tracing.
266
44
									frame_system::BlockWeight::<Runtime>::kill();
267
44

            
268
44
									let tx_hash = &transaction.hash();
269
44
									if known_transactions.contains(&tx_hash) {
270
44
										// Each known extrinsic is a new call stack.
271
44
										EvmTracer::emit_new();
272
44
										EvmTracer::new().trace(|| {
273
											if let Err(err) = Executive::apply_extrinsic(ext) {
274
												log::debug!(
275
													target: "tracing",
276
													"Could not trace eth transaction (hash: {}): {:?}",
277
													&tx_hash,
278
													err
279
												);
280
											}
281
44
										});
282
44
									} else {
283
										if let Err(err) = Executive::apply_extrinsic(ext) {
284
											log::debug!(
285
												target: "tracing",
286
												"Failed to apply eth extrinsic (hash: {}): {:?}",
287
												&tx_hash,
288
												err
289
											);
290
										}
291
									}
292
								}
293
								_ => {
294
44
									if let Err(err) = Executive::apply_extrinsic(ext) {
295
										log::debug!(
296
											target: "tracing",
297
											"Failed to apply non-eth extrinsic: {:?}",
298
											err
299
										);
300
									}
301
								}
302
							};
303
						}
304

            
305
						// Replay on_idle
306
						// Some XCM messages with eth-xcm transaction might be executed at on_idle
307
22
						replay_on_idle();
308
22

            
309
22
						Ok(())
310
22
					}
311
22
					#[cfg(not(feature = "evm-tracing"))]
312
22
					Err(sp_runtime::DispatchError::Other(
313
22
						"Missing `evm-tracing` compile time feature flag.",
314
22
					))
315
22
				}
316

            
317
22
				fn trace_call(
318
22
					header: &<Block as BlockT>::Header,
319
22
					from: H160,
320
22
					to: H160,
321
22
					data: Vec<u8>,
322
22
					value: U256,
323
22
					gas_limit: U256,
324
22
					max_fee_per_gas: Option<U256>,
325
22
					max_priority_fee_per_gas: Option<U256>,
326
22
					nonce: Option<U256>,
327
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
328
22
				) -> Result<(), sp_runtime::DispatchError> {
329
22
					#[cfg(feature = "evm-tracing")]
330
22
					{
331
22
						use moonbeam_evm_tracer::tracer::EvmTracer;
332
22

            
333
22
						// Initialize block: calls the "on_initialize" hook on every pallet
334
22
						// in AllPalletsWithSystem.
335
22
						Executive::initialize_block(header);
336
22

            
337
22
						EvmTracer::new().trace(|| {
338
							let is_transactional = false;
339
							let validate = true;
340
							let without_base_extrinsic_weight = true;
341

            
342

            
343
							// Estimated encoded transaction size must be based on the heaviest transaction
344
							// type (EIP1559Transaction) to be compatible with all transaction types.
345
							// TODO: remove, since we will get rid of base_cost
346
							let mut estimated_transaction_len = data.len() +
347
								// pallet ethereum index: 1
348
								// transact call index: 1
349
								// Transaction enum variant: 1
350
								// chain_id 8 bytes
351
								// nonce: 32
352
								// max_priority_fee_per_gas: 32
353
								// max_fee_per_gas: 32
354
								// gas_limit: 32
355
								// action: 21 (enum varianrt + call address)
356
								// value: 32
357
								// access_list: 1 (empty vec size)
358
								// 65 bytes signature
359
								258;
360

            
361
							if access_list.is_some() {
362
								estimated_transaction_len += access_list.encoded_size();
363
							}
364

            
365
							let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
366

            
367
							let (weight_limit, proof_size_base_cost) =
368
								match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
369
									gas_limit,
370
									without_base_extrinsic_weight
371
								) {
372
									weight_limit if weight_limit.proof_size() > 0 => {
373
										(Some(weight_limit), Some(estimated_transaction_len as u64))
374
									}
375
									_ => (None, None),
376
								};
377

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

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

            
428
			impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
429
22
				fn chain_id() -> u64 {
430
22
					<Runtime as pallet_evm::Config>::ChainId::get()
431
22
				}
432

            
433
22
				fn account_basic(address: H160) -> EVMAccount {
434
22
					let (account, _) = EVM::account_basic(&address);
435
22
					account
436
22
				}
437

            
438
22
				fn gas_price() -> U256 {
439
22
					let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
440
22
					gas_price
441
22
				}
442

            
443
22
				fn account_code_at(address: H160) -> Vec<u8> {
444
22
					pallet_evm::AccountCodes::<Runtime>::get(address)
445
22
				}
446

            
447
22
				fn author() -> H160 {
448
22
					<pallet_evm::Pallet<Runtime>>::find_author()
449
22
				}
450

            
451
22
				fn storage_at(address: H160, index: U256) -> H256 {
452
22
					let mut tmp = [0u8; 32];
453
22
					index.to_big_endian(&mut tmp);
454
22
					pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
455
22
				}
456

            
457
22
				fn call(
458
22
					from: H160,
459
22
					to: H160,
460
22
					data: Vec<u8>,
461
22
					value: U256,
462
22
					gas_limit: U256,
463
22
					max_fee_per_gas: Option<U256>,
464
22
					max_priority_fee_per_gas: Option<U256>,
465
22
					nonce: Option<U256>,
466
22
					estimate: bool,
467
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
468
22
				) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
469
22
					let config = if estimate {
470
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
471
						config.estimate = true;
472
						Some(config)
473
					} else {
474
22
						None
475
					};
476
22
					let is_transactional = false;
477
22
					let validate = true;
478
22

            
479
22
							// Estimated encoded transaction size must be based on the heaviest transaction
480
22
							// type (EIP1559Transaction) to be compatible with all transaction types.
481
22
					// TODO: remove, since we will get rid of base_cost
482
22
					let mut estimated_transaction_len = data.len() +
483
22
						// pallet ethereum index: 1
484
22
						// transact call index: 1
485
22
						// Transaction enum variant: 1
486
22
						// chain_id 8 bytes
487
22
						// nonce: 32
488
22
						// max_priority_fee_per_gas: 32
489
22
						// max_fee_per_gas: 32
490
22
						// gas_limit: 32
491
22
						// action: 21 (enum varianrt + call address)
492
22
						// value: 32
493
22
						// access_list: 1 (empty vec size)
494
22
						// 65 bytes signature
495
22
						258;
496
22

            
497
22
					if access_list.is_some() {
498
						estimated_transaction_len += access_list.encoded_size();
499
					}
500

            
501
22
					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
502
22
					let without_base_extrinsic_weight = true;
503

            
504
22
					let (weight_limit, proof_size_base_cost) =
505
22
						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
506
22
							gas_limit,
507
22
							without_base_extrinsic_weight
508
22
						) {
509
22
							weight_limit if weight_limit.proof_size() > 0 => {
510
22
								(Some(weight_limit), Some(estimated_transaction_len as u64))
511
							}
512
							_ => (None, None),
513
						};
514

            
515
22
					<Runtime as pallet_evm::Config>::Runner::call(
516
22
						from,
517
22
						to,
518
22
						data,
519
22
						value,
520
22
						gas_limit,
521
22
						max_fee_per_gas,
522
22
						max_priority_fee_per_gas,
523
22
						nonce,
524
22
						access_list.unwrap_or_default(),
525
22
						is_transactional,
526
22
						validate,
527
22
						weight_limit,
528
22
						proof_size_base_cost,
529
22
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
530
22
					).map_err(|err| err.error.into())
531
22
				}
532

            
533
22
				fn create(
534
22
					from: H160,
535
22
					data: Vec<u8>,
536
22
					value: U256,
537
22
					gas_limit: U256,
538
22
					max_fee_per_gas: Option<U256>,
539
22
					max_priority_fee_per_gas: Option<U256>,
540
22
					nonce: Option<U256>,
541
22
					estimate: bool,
542
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
543
22
				) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
544
22
					let config = if estimate {
545
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
546
						config.estimate = true;
547
						Some(config)
548
					} else {
549
22
						None
550
					};
551
22
					let is_transactional = false;
552
22
					let validate = true;
553
22

            
554
22
					let mut estimated_transaction_len = data.len() +
555
22
						// from: 20
556
22
						// value: 32
557
22
						// gas_limit: 32
558
22
						// nonce: 32
559
22
						// 1 byte transaction action variant
560
22
						// chain id 8 bytes
561
22
						// 65 bytes signature
562
22
						190;
563
22

            
564
22
					if max_fee_per_gas.is_some() {
565
						estimated_transaction_len += 32;
566
					}
567
22
					if max_priority_fee_per_gas.is_some() {
568
						estimated_transaction_len += 32;
569
					}
570
22
					if access_list.is_some() {
571
						estimated_transaction_len += access_list.encoded_size();
572
					}
573

            
574
22
					let gas_limit = if gas_limit > U256::from(u64::MAX) {
575
						u64::MAX
576
					} else {
577
22
						gas_limit.low_u64()
578
					};
579
22
					let without_base_extrinsic_weight = true;
580

            
581
22
					let (weight_limit, proof_size_base_cost) =
582
22
						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
583
22
							gas_limit,
584
22
							without_base_extrinsic_weight
585
22
						) {
586
22
							weight_limit if weight_limit.proof_size() > 0 => {
587
22
								(Some(weight_limit), Some(estimated_transaction_len as u64))
588
							}
589
							_ => (None, None),
590
						};
591

            
592
					#[allow(clippy::or_fun_call)] // suggestion not helpful here
593
22
					<Runtime as pallet_evm::Config>::Runner::create(
594
22
						from,
595
22
						data,
596
22
						value,
597
22
						gas_limit,
598
22
						max_fee_per_gas,
599
22
						max_priority_fee_per_gas,
600
22
						nonce,
601
22
						access_list.unwrap_or_default(),
602
22
						is_transactional,
603
22
						validate,
604
22
						weight_limit,
605
22
						proof_size_base_cost,
606
22
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
607
22
					).map_err(|err| err.error.into())
608
22
				}
609

            
610
22
				fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
611
22
					pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
612
22
				}
613

            
614
22
				fn current_block() -> Option<pallet_ethereum::Block> {
615
22
					pallet_ethereum::CurrentBlock::<Runtime>::get()
616
22
				}
617

            
618
22
				fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
619
22
					pallet_ethereum::CurrentReceipts::<Runtime>::get()
620
22
				}
621

            
622
				fn current_all() -> (
623
					Option<pallet_ethereum::Block>,
624
					Option<Vec<pallet_ethereum::Receipt>>,
625
					Option<Vec<TransactionStatus>>,
626
				) {
627
					(
628
						pallet_ethereum::CurrentBlock::<Runtime>::get(),
629
						pallet_ethereum::CurrentReceipts::<Runtime>::get(),
630
						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get(),
631
					)
632
				}
633

            
634
				fn extrinsic_filter(
635
					xts: Vec<<Block as BlockT>::Extrinsic>,
636
				) -> Vec<EthereumTransaction> {
637
					xts.into_iter().filter_map(|xt| match xt.0.function {
638
						RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
639
						_ => None
640
					}).collect::<Vec<EthereumTransaction>>()
641
				}
642

            
643
				fn elasticity() -> Option<Permill> {
644
					None
645
				}
646

            
647
				fn gas_limit_multiplier_support() {}
648

            
649
				fn pending_block(
650
					xts: Vec<<Block as sp_runtime::traits::Block>::Extrinsic>
651
				) -> (
652
					Option<pallet_ethereum::Block>, Option<sp_std::prelude::Vec<TransactionStatus>>
653
				) {
654
					for ext in xts.into_iter() {
655
						let _ = Executive::apply_extrinsic(ext);
656
					}
657

            
658
					Ethereum::on_finalize(System::block_number() + 1);
659

            
660
					(
661
						pallet_ethereum::CurrentBlock::<Runtime>::get(),
662
						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
663
					)
664
				 }
665

            
666
				fn initialize_pending_block(header: &<Block as BlockT>::Header) {
667
					pallet_randomness::vrf::using_fake_vrf(|| {
668
						let _ = Executive::initialize_block(header);
669
					})
670
				}
671
			}
672

            
673
			impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
674
				fn convert_transaction(
675
					transaction: pallet_ethereum::Transaction
676
				) -> <Block as BlockT>::Extrinsic {
677
					UncheckedExtrinsic::new_unsigned(
678
						pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
679
					)
680
				}
681
			}
682

            
683
			impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
684
			for Runtime {
685
				fn query_info(
686
					uxt: <Block as BlockT>::Extrinsic,
687
					len: u32,
688
				) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
689
					TransactionPayment::query_info(uxt, len)
690
				}
691

            
692
				fn query_fee_details(
693
					uxt: <Block as BlockT>::Extrinsic,
694
					len: u32,
695
				) -> pallet_transaction_payment::FeeDetails<Balance> {
696
					TransactionPayment::query_fee_details(uxt, len)
697
				}
698

            
699
				fn query_weight_to_fee(weight: Weight) -> Balance {
700
					TransactionPayment::weight_to_fee(weight)
701
				}
702

            
703
				fn query_length_to_fee(length: u32) -> Balance {
704
					TransactionPayment::length_to_fee(length)
705
				}
706
			}
707

            
708
			impl nimbus_primitives::NimbusApi<Block> for Runtime {
709
66
				fn can_author(
710
66
					author: nimbus_primitives::NimbusId,
711
66
					slot: u32,
712
66
					parent_header: &<Block as BlockT>::Header
713
66
				) -> bool {
714
66
					use pallet_parachain_staking::Config as PalletParachainStakingConfig;
715
66

            
716
66
					let block_number = parent_header.number + 1;
717
66

            
718
66
					// The Moonbeam runtimes use an entropy source that needs to do some accounting
719
66
					// work during block initialization. Therefore we initialize it here to match
720
66
					// the state it will be in when the next block is being executed.
721
66
					use frame_support::traits::OnInitialize;
722
66
					System::initialize(
723
66
						&block_number,
724
66
						&parent_header.hash(),
725
66
						&parent_header.digest,
726
66
					);
727
66

            
728
66
					// Because the staking solution calculates the next staking set at the beginning
729
66
					// of the first block in the new round, the only way to accurately predict the
730
66
					// authors is to compute the selection during prediction.
731
66
					if pallet_parachain_staking::Pallet::<Self>::round()
732
66
						.should_update(block_number) {
733
						// get author account id
734
						use nimbus_primitives::AccountLookup;
735
						let author_account_id = if let Some(account) =
736
							pallet_author_mapping::Pallet::<Self>::lookup_account(&author) {
737
							account
738
						} else {
739
							// return false if author mapping not registered like in can_author impl
740
							return false
741
						};
742
						let candidates = pallet_parachain_staking::Pallet::<Self>::compute_top_candidates();
743
						if candidates.is_empty() {
744
							// If there are zero selected candidates, we use the same eligibility
745
							// as the previous round
746
							return AuthorInherent::can_author(&author, &slot);
747
						}
748

            
749
						// predict eligibility post-selection by computing selection results now
750
						let (eligible, _) =
751
							pallet_author_slot_filter::compute_pseudo_random_subset::<Self>(
752
								candidates,
753
								&slot
754
							);
755
						eligible.contains(&author_account_id)
756
					} else {
757
66
						AuthorInherent::can_author(&author, &slot)
758
					}
759
				}
760
			}
761

            
762
			impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
763
				fn collect_collation_info(
764
					header: &<Block as BlockT>::Header
765
				) -> cumulus_primitives_core::CollationInfo {
766
					ParachainSystem::collect_collation_info(header)
767
				}
768
			}
769

            
770
			impl session_keys_primitives::VrfApi<Block> for Runtime {
771
				fn get_last_vrf_output() -> Option<<Block as BlockT>::Hash> {
772
					// TODO: remove in future runtime upgrade along with storage item
773
					if pallet_randomness::Pallet::<Self>::not_first_block().is_none() {
774
						return None;
775
					}
776
					pallet_randomness::Pallet::<Self>::local_vrf_output()
777
				}
778
				fn vrf_key_lookup(
779
					nimbus_id: nimbus_primitives::NimbusId
780
				) -> Option<session_keys_primitives::VrfId> {
781
					use session_keys_primitives::KeysLookup;
782
					AuthorMapping::lookup_keys(&nimbus_id)
783
				}
784
			}
785

            
786
			impl xcm_runtime_apis::fees::XcmPaymentApi<Block> for Runtime {
787
				fn query_acceptable_payment_assets(
788
					xcm_version: xcm::Version
789
				) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
790
					XcmWeightTrader::query_acceptable_payment_assets(xcm_version)
791
				}
792

            
793
				fn query_weight_to_asset_fee(
794
					weight: Weight, asset: VersionedAssetId
795
				) -> Result<u128, XcmPaymentApiError> {
796
					XcmWeightTrader::query_weight_to_asset_fee(weight, asset)
797
				}
798

            
799
				fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
800
					PolkadotXcm::query_xcm_weight(message)
801
				}
802

            
803
				fn query_delivery_fees(
804
					destination: VersionedLocation, message: VersionedXcm<()>
805
				) -> Result<VersionedAssets, XcmPaymentApiError> {
806
					PolkadotXcm::query_delivery_fees(destination, message)
807
				}
808
			}
809

            
810
			impl xcm_runtime_apis::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller>
811
				for Runtime {
812
					fn dry_run_call(
813
						origin: OriginCaller,
814
						call: RuntimeCall
815
					) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
816
						PolkadotXcm::dry_run_call::<
817
							Runtime,
818
							xcm_config::XcmRouter,
819
							OriginCaller,
820
							RuntimeCall>(origin, call)
821
					}
822

            
823
					fn dry_run_xcm(
824
						origin_location: VersionedLocation,
825
						xcm: VersionedXcm<RuntimeCall>
826
					) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
827
						PolkadotXcm::dry_run_xcm::<
828
							Runtime,
829
							xcm_config::XcmRouter,
830
							RuntimeCall,
831
							xcm_config::XcmExecutorConfig>(origin_location, xcm)
832
					}
833
				}
834

            
835
			impl xcm_runtime_apis::conversions::LocationToAccountApi<Block, AccountId> for Runtime {
836
				fn convert_location(location: VersionedLocation) -> Result<
837
					AccountId,
838
					xcm_runtime_apis::conversions::Error
839
				> {
840
					xcm_runtime_apis::conversions::LocationToAccountHelper::<
841
						AccountId,
842
						xcm_config::LocationToAccountId,
843
					>::convert_location(location)
844
				}
845
			}
846

            
847
			#[cfg(feature = "runtime-benchmarks")]
848
			impl frame_benchmarking::Benchmark<Block> for Runtime {
849

            
850
				fn benchmark_metadata(extra: bool) -> (
851
					Vec<frame_benchmarking::BenchmarkList>,
852
					Vec<frame_support::traits::StorageInfo>,
853
				) {
854
					use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
855
					use frame_system_benchmarking::Pallet as SystemBench;
856
					use moonbeam_xcm_benchmarks::generic::benchmarking as MoonbeamXcmBenchmarks;
857
					use frame_support::traits::StorageInfoTrait;
858
					use MoonbeamXcmBenchmarks::XcmGenericBenchmarks as MoonbeamXcmGenericBench;
859

            
860
					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
861

            
862
					let mut list = Vec::<BenchmarkList>::new();
863
					list_benchmarks!(list, extra);
864

            
865
					let storage_info = AllPalletsWithSystem::storage_info();
866

            
867
					return (list, storage_info)
868
				}
869

            
870
				fn dispatch_benchmark(
871
					config: frame_benchmarking::BenchmarkConfig,
872
				) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
873
					use frame_benchmarking::{add_benchmark, BenchmarkBatch, Benchmarking};
874
					use frame_support::traits::TrackedStorageKey;
875
					use cumulus_primitives_core::ParaId;
876

            
877
					use xcm::latest::prelude::{
878
						GeneralIndex, Junction, Junctions, Location, Response, NetworkId, AssetId,
879
						Assets as XcmAssets, Fungible, Asset, ParentThen, Parachain, Parent
880
					};
881
					use xcm_config::SelfReserve;
882
					use frame_benchmarking::BenchmarkError;
883

            
884
					use frame_system_benchmarking::Pallet as SystemBench;
885
					// Needed to run `set_code` and `apply_authorized_upgrade` frame_system benchmarks
886
					// https://github.com/paritytech/cumulus/pull/2766
887
					impl frame_system_benchmarking::Config for Runtime {
888
						fn setup_set_code_requirements(code: &Vec<u8>) -> Result<(), BenchmarkError> {
889
							ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
890
							Ok(())
891
						}
892

            
893
						fn verify_set_code() {
894
							System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
895
						}
896
					}
897

            
898
					impl moonbeam_xcm_benchmarks::Config for Runtime {}
899
					impl moonbeam_xcm_benchmarks::generic::Config for Runtime {}
900

            
901
					use pallet_asset_manager::Config as PalletAssetManagerConfig;
902

            
903
					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
904
					parameter_types! {
905
						pub const RandomParaId: ParaId = ParaId::new(43211234);
906
					}
907

            
908
					pub struct TestDeliveryHelper;
909
					impl xcm_builder::EnsureDelivery for TestDeliveryHelper {
910
						fn ensure_successful_delivery(
911
							origin_ref: &Location,
912
							_dest: &Location,
913
							_fee_reason: xcm_executor::traits::FeeReason,
914
						) -> (Option<xcm_executor::FeesMode>, Option<XcmAssets>) {
915
							use xcm_executor::traits::ConvertLocation;
916
							let account = xcm_config::LocationToH160::convert_location(origin_ref)
917
								.expect("Invalid location");
918
							// Give the existential deposit at least
919
							let balance = ExistentialDeposit::get();
920
							let _ = <Balances as frame_support::traits::Currency<_>>::
921
								make_free_balance_be(&account.into(), balance);
922

            
923
							(None, None)
924
						}
925
					}
926

            
927
					impl pallet_xcm::benchmarking::Config for Runtime {
928
				        type DeliveryHelper = TestDeliveryHelper;
929

            
930
						fn get_asset() -> Asset {
931
							Asset {
932
								id: AssetId(SelfReserve::get()),
933
								fun: Fungible(ExistentialDeposit::get()),
934
							}
935
						}
936

            
937
						fn reachable_dest() -> Option<Location> {
938
							Some(Parent.into())
939
						}
940

            
941
						fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
942
							None
943
						}
944

            
945
						fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
946
							use xcm_config::SelfReserve;
947

            
948
							ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
949
								RandomParaId::get().into()
950
							);
951

            
952
							Some((
953
								Asset {
954
									fun: Fungible(ExistentialDeposit::get()),
955
									id: AssetId(SelfReserve::get().into())
956
								},
957
								// Moonbeam can reserve transfer native token to
958
								// some random parachain.
959
								ParentThen(Parachain(RandomParaId::get().into()).into()).into(),
960
							))
961
						}
962

            
963
						fn set_up_complex_asset_transfer(
964
						) -> Option<(XcmAssets, u32, Location, Box<dyn FnOnce()>)> {
965
							use xcm_config::SelfReserve;
966

            
967
							let destination: xcm::v4::Location = Parent.into();
968

            
969
							let fee_amount: u128 = <Runtime as pallet_balances::Config>::ExistentialDeposit::get();
970
							let fee_asset: Asset = (SelfReserve::get(), fee_amount).into();
971

            
972
							// Give some multiple of transferred amount
973
							let balance = fee_amount * 1000;
974
							let who = frame_benchmarking::whitelisted_caller();
975
							let _ =
976
								<Balances as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
977

            
978
							// verify initial balance
979
							assert_eq!(Balances::free_balance(&who), balance);
980

            
981
							// set up local asset
982
							let asset_amount: u128 = 10u128;
983
							let initial_asset_amount: u128 = asset_amount * 10;
984

            
985
							let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::<
986
								Runtime,
987
								()
988
							>(true, initial_asset_amount);
989
							let transfer_asset: Asset = (SelfReserve::get(), asset_amount).into();
990

            
991
							let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into();
992
							let fee_index: u32 = 0;
993

            
994
							let verify: Box<dyn FnOnce()> = Box::new(move || {
995
								// verify balance after transfer, decreased by
996
								// transferred amount (and delivery fees)
997
								assert!(Balances::free_balance(&who) <= balance - fee_amount);
998
							});
999

            
							Some((assets, fee_index, destination, verify))
						}
					}
					impl pallet_xcm_benchmarks::Config for Runtime {
						type XcmConfig = xcm_config::XcmExecutorConfig;
						type AccountIdConverter = xcm_config::LocationToAccountId;
						type DeliveryHelper = ();
						fn valid_destination() -> Result<Location, BenchmarkError> {
							Ok(Location::parent())
						}
						fn worst_case_holding(_depositable_count: u32) -> XcmAssets {
						// 100 fungibles
							const HOLDING_FUNGIBLES: u32 = 100;
							let fungibles_amount: u128 = 100;
							let assets = (0..HOLDING_FUNGIBLES).map(|i| {
								let location: Location = GeneralIndex(i as u128).into();
								Asset {
									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 fee_asset() -> Result<Asset, 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)
						}
					}
					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")
				}
			}
		}
	};
}