1
// Copyright 2019-2022 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
			impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
119
				fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
120
					frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(config)
121
				}
122

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

            
127
				fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
128
					vec![]
129
				}
130
			}
131

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

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

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

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

            
170
						// Apply the a subset of extrinsics: all the substrate-specific or ethereum
171
						// transactions that preceded the requested transaction.
172
44
						for ext in extrinsics.into_iter() {
173
22
							let _ = match &ext.0.function {
174
22
								RuntimeCall::Ethereum(transact { transaction }) => {
175
22
									if transaction == traced_transaction {
176
22
										EvmTracer::new().trace(|| Executive::apply_extrinsic(ext));
177
22
										return Ok(());
178
									} else {
179
										Executive::apply_extrinsic(ext)
180
									}
181
								}
182
22
								_ => Executive::apply_extrinsic(ext),
183
							};
184
22
							if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get(
185
22
								ETHEREUM_XCM_TRACING_STORAGE_KEY
186
22
							) {
187
								return Ok(());
188
							}
189
						}
190

            
191
						if let Some(EthereumXcmTracingStatus::Transaction(_)) = unhashed::get(
192
							ETHEREUM_XCM_TRACING_STORAGE_KEY
193
						) {
194
							// If the transaction was not found, it might be
195
							// an eth-xcm transaction that was executed at on_idle
196
							replay_on_idle();
197
						}
198

            
199
						if let Some(EthereumXcmTracingStatus::TransactionExited) = unhashed::get(
200
							ETHEREUM_XCM_TRACING_STORAGE_KEY
201
						) {
202
							// The transaction was found
203
							Ok(())
204
						} else {
205
							// The transaction was not-found
206
							Err(sp_runtime::DispatchError::Other(
207
								"Failed to find Ethereum transaction among the extrinsics.",
208
							))
209
						}
210
					}
211
					#[cfg(not(feature = "evm-tracing"))]
212
					Err(sp_runtime::DispatchError::Other(
213
						"Missing `evm-tracing` compile time feature flag.",
214
					))
215
				}
216

            
217
22
				fn trace_block(
218
22
					extrinsics: Vec<<Block as BlockT>::Extrinsic>,
219
22
					known_transactions: Vec<H256>,
220
22
					header: &<Block as BlockT>::Header,
221
22
				) -> Result<
222
22
					(),
223
22
					sp_runtime::DispatchError,
224
22
				> {
225
22
					#[cfg(feature = "evm-tracing")]
226
22
					{
227
22
						use moonbeam_evm_tracer::tracer::EvmTracer;
228
22
						use frame_system::pallet_prelude::BlockNumberFor;
229
22
						use xcm_primitives::EthereumXcmTracingStatus;
230
22

            
231
22
						// Tell the CallDispatcher we are tracing a full Block.
232
22
						frame_support::storage::unhashed::put::<EthereumXcmTracingStatus>(
233
22
							xcm_primitives::ETHEREUM_XCM_TRACING_STORAGE_KEY,
234
22
							&EthereumXcmTracingStatus::Block,
235
22
						);
236
22

            
237
22
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
238
22
						config.estimate = true;
239
22

            
240
22
						// Initialize block: calls the "on_initialize" hook on every pallet
241
22
						// in AllPalletsWithSystem.
242
22
						// After pallet message queue was introduced, this must be done only after
243
22
						// enabling XCM tracing by setting ETHEREUM_XCM_TRACING_STORAGE_KEY
244
22
						// in the storage
245
22
						Executive::initialize_block(header);
246

            
247
						// Apply all extrinsics. Ethereum extrinsics are traced.
248
88
						for ext in extrinsics.into_iter() {
249
44
							match &ext.0.function {
250
44
								RuntimeCall::Ethereum(transact { transaction }) => {
251
44
									if known_transactions.contains(&transaction.hash()) {
252
44
										// Each known extrinsic is a new call stack.
253
44
										EvmTracer::emit_new();
254
44
										EvmTracer::new().trace(|| Executive::apply_extrinsic(ext));
255
44
									} else {
256
										let _ = Executive::apply_extrinsic(ext);
257
									}
258
								}
259
44
								_ => {
260
44
									let _ = Executive::apply_extrinsic(ext);
261
44
								}
262
							};
263
						}
264

            
265
						// Replay on_idle
266
						// Some XCM messages with eth-xcm transaction might be executed at on_idle
267
22
						replay_on_idle();
268
22

            
269
22
						Ok(())
270
22
					}
271
22
					#[cfg(not(feature = "evm-tracing"))]
272
22
					Err(sp_runtime::DispatchError::Other(
273
22
						"Missing `evm-tracing` compile time feature flag.",
274
22
					))
275
22
				}
276

            
277
22
				fn trace_call(
278
22
					header: &<Block as BlockT>::Header,
279
22
					from: H160,
280
22
					to: H160,
281
22
					data: Vec<u8>,
282
22
					value: U256,
283
22
					gas_limit: U256,
284
22
					max_fee_per_gas: Option<U256>,
285
22
					max_priority_fee_per_gas: Option<U256>,
286
22
					nonce: Option<U256>,
287
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
288
22
				) -> Result<(), sp_runtime::DispatchError> {
289
22
					#[cfg(feature = "evm-tracing")]
290
22
					{
291
22
						use moonbeam_evm_tracer::tracer::EvmTracer;
292
22

            
293
22
						// Initialize block: calls the "on_initialize" hook on every pallet
294
22
						// in AllPalletsWithSystem.
295
22
						Executive::initialize_block(header);
296
22

            
297
22
						EvmTracer::new().trace(|| {
298
							let is_transactional = false;
299
							let validate = true;
300
							let without_base_extrinsic_weight = true;
301

            
302

            
303
							// Estimated encoded transaction size must be based on the heaviest transaction
304
							// type (EIP1559Transaction) to be compatible with all transaction types.
305
							let mut estimated_transaction_len = data.len() +
306
							// pallet ethereum index: 1
307
							// transact call index: 1
308
							// Transaction enum variant: 1
309
							// chain_id 8 bytes
310
							// nonce: 32
311
							// max_priority_fee_per_gas: 32
312
							// max_fee_per_gas: 32
313
							// gas_limit: 32
314
							// action: 21 (enum varianrt + call address)
315
							// value: 32
316
							// access_list: 1 (empty vec size)
317
							// 65 bytes signature
318
							258;
319

            
320
							if access_list.is_some() {
321
								estimated_transaction_len += access_list.encoded_size();
322
							}
323

            
324
							let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
325

            
326
							let (weight_limit, proof_size_base_cost) =
327
								match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
328
									gas_limit,
329
									without_base_extrinsic_weight
330
								) {
331
									weight_limit if weight_limit.proof_size() > 0 => {
332
										(Some(weight_limit), Some(estimated_transaction_len as u64))
333
									}
334
									_ => (None, None),
335
								};
336

            
337
							let _ = <Runtime as pallet_evm::Config>::Runner::call(
338
								from,
339
								to,
340
								data,
341
								value,
342
								gas_limit,
343
								max_fee_per_gas,
344
								max_priority_fee_per_gas,
345
								nonce,
346
								access_list.unwrap_or_default(),
347
								is_transactional,
348
								validate,
349
								weight_limit,
350
								proof_size_base_cost,
351
								<Runtime as pallet_evm::Config>::config(),
352
							);
353
22
						});
354
22
						Ok(())
355
22
					}
356
22
					#[cfg(not(feature = "evm-tracing"))]
357
22
					Err(sp_runtime::DispatchError::Other(
358
22
						"Missing `evm-tracing` compile time feature flag.",
359
22
					))
360
22
				}
361
			}
362

            
363
			impl moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block> for Runtime {
364
22
				fn extrinsic_filter(
365
22
					xts_ready: Vec<<Block as BlockT>::Extrinsic>,
366
22
					xts_future: Vec<<Block as BlockT>::Extrinsic>,
367
22
				) -> TxPoolResponse {
368
22
					TxPoolResponse {
369
22
						ready: xts_ready
370
22
							.into_iter()
371
22
							.filter_map(|xt| match xt.0.function {
372
								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
373
								_ => None,
374
22
							})
375
22
							.collect(),
376
22
						future: xts_future
377
22
							.into_iter()
378
22
							.filter_map(|xt| match xt.0.function {
379
								RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
380
								_ => None,
381
22
							})
382
22
							.collect(),
383
22
					}
384
22
				}
385
			}
386

            
387
			impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
388
22
				fn chain_id() -> u64 {
389
22
					<Runtime as pallet_evm::Config>::ChainId::get()
390
22
				}
391

            
392
22
				fn account_basic(address: H160) -> EVMAccount {
393
22
					let (account, _) = EVM::account_basic(&address);
394
22
					account
395
22
				}
396

            
397
22
				fn gas_price() -> U256 {
398
22
					let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
399
22
					gas_price
400
22
				}
401

            
402
22
				fn account_code_at(address: H160) -> Vec<u8> {
403
22
					pallet_evm::AccountCodes::<Runtime>::get(address)
404
22
				}
405

            
406
22
				fn author() -> H160 {
407
22
					<pallet_evm::Pallet<Runtime>>::find_author()
408
22
				}
409

            
410
22
				fn storage_at(address: H160, index: U256) -> H256 {
411
22
					let mut tmp = [0u8; 32];
412
22
					index.to_big_endian(&mut tmp);
413
22
					pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
414
22
				}
415

            
416
22
				fn call(
417
22
					from: H160,
418
22
					to: H160,
419
22
					data: Vec<u8>,
420
22
					value: U256,
421
22
					gas_limit: U256,
422
22
					max_fee_per_gas: Option<U256>,
423
22
					max_priority_fee_per_gas: Option<U256>,
424
22
					nonce: Option<U256>,
425
22
					estimate: bool,
426
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
427
22
				) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
428
22
					let config = if estimate {
429
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
430
						config.estimate = true;
431
						Some(config)
432
					} else {
433
22
						None
434
					};
435
22
					let is_transactional = false;
436
22
					let validate = true;
437
22

            
438
22
					// Estimated encoded transaction size must be based on the heaviest transaction
439
22
					// type (EIP1559Transaction) to be compatible with all transaction types.
440
22
					let mut estimated_transaction_len = data.len() +
441
22
						// pallet ethereum index: 1
442
22
						// transact call index: 1
443
22
						// Transaction enum variant: 1
444
22
						// chain_id 8 bytes
445
22
						// nonce: 32
446
22
						// max_priority_fee_per_gas: 32
447
22
						// max_fee_per_gas: 32
448
22
						// gas_limit: 32
449
22
						// action: 21 (enum varianrt + call address)
450
22
						// value: 32
451
22
						// access_list: 1 (empty vec size)
452
22
						// 65 bytes signature
453
22
						258;
454
22

            
455
22
					if access_list.is_some() {
456
						estimated_transaction_len += access_list.encoded_size();
457
					}
458

            
459
22
					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
460
22
					let without_base_extrinsic_weight = true;
461

            
462
22
					let (weight_limit, proof_size_base_cost) =
463
22
						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
464
22
							gas_limit,
465
22
							without_base_extrinsic_weight
466
22
						) {
467
22
							weight_limit if weight_limit.proof_size() > 0 => {
468
22
								(Some(weight_limit), Some(estimated_transaction_len as u64))
469
							}
470
							_ => (None, None),
471
						};
472

            
473
22
					<Runtime as pallet_evm::Config>::Runner::call(
474
22
						from,
475
22
						to,
476
22
						data,
477
22
						value,
478
22
						gas_limit,
479
22
						max_fee_per_gas,
480
22
						max_priority_fee_per_gas,
481
22
						nonce,
482
22
						access_list.unwrap_or_default(),
483
22
						is_transactional,
484
22
						validate,
485
22
						weight_limit,
486
22
						proof_size_base_cost,
487
22
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
488
22
					).map_err(|err| err.error.into())
489
22
				}
490

            
491
22
				fn create(
492
22
					from: H160,
493
22
					data: Vec<u8>,
494
22
					value: U256,
495
22
					gas_limit: U256,
496
22
					max_fee_per_gas: Option<U256>,
497
22
					max_priority_fee_per_gas: Option<U256>,
498
22
					nonce: Option<U256>,
499
22
					estimate: bool,
500
22
					access_list: Option<Vec<(H160, Vec<H256>)>>,
501
22
				) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
502
22
					let config = if estimate {
503
						let mut config = <Runtime as pallet_evm::Config>::config().clone();
504
						config.estimate = true;
505
						Some(config)
506
					} else {
507
22
						None
508
					};
509
22
					let is_transactional = false;
510
22
					let validate = true;
511
22

            
512
22
					let mut estimated_transaction_len = data.len() +
513
22
						// from: 20
514
22
						// value: 32
515
22
						// gas_limit: 32
516
22
						// nonce: 32
517
22
						// 1 byte transaction action variant
518
22
						// chain id 8 bytes
519
22
						// 65 bytes signature
520
22
						190;
521
22

            
522
22
					if max_fee_per_gas.is_some() {
523
						estimated_transaction_len += 32;
524
					}
525
22
					if max_priority_fee_per_gas.is_some() {
526
						estimated_transaction_len += 32;
527
					}
528
22
					if access_list.is_some() {
529
						estimated_transaction_len += access_list.encoded_size();
530
					}
531

            
532
22
					let gas_limit = if gas_limit > U256::from(u64::MAX) {
533
						u64::MAX
534
					} else {
535
22
						gas_limit.low_u64()
536
					};
537
22
					let without_base_extrinsic_weight = true;
538

            
539
22
					let (weight_limit, proof_size_base_cost) =
540
22
						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
541
22
							gas_limit,
542
22
							without_base_extrinsic_weight
543
22
						) {
544
22
							weight_limit if weight_limit.proof_size() > 0 => {
545
22
								(Some(weight_limit), Some(estimated_transaction_len as u64))
546
							}
547
							_ => (None, None),
548
						};
549

            
550
					#[allow(clippy::or_fun_call)] // suggestion not helpful here
551
22
					<Runtime as pallet_evm::Config>::Runner::create(
552
22
						from,
553
22
						data,
554
22
						value,
555
22
						gas_limit,
556
22
						max_fee_per_gas,
557
22
						max_priority_fee_per_gas,
558
22
						nonce,
559
22
						access_list.unwrap_or_default(),
560
22
						is_transactional,
561
22
						validate,
562
22
						weight_limit,
563
22
						proof_size_base_cost,
564
22
						config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
565
22
					).map_err(|err| err.error.into())
566
22
				}
567

            
568
22
				fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
569
22
					pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
570
22
				}
571

            
572
22
				fn current_block() -> Option<pallet_ethereum::Block> {
573
22
					pallet_ethereum::CurrentBlock::<Runtime>::get()
574
22
				}
575

            
576
22
				fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
577
22
					pallet_ethereum::CurrentReceipts::<Runtime>::get()
578
22
				}
579

            
580
				fn current_all() -> (
581
					Option<pallet_ethereum::Block>,
582
					Option<Vec<pallet_ethereum::Receipt>>,
583
					Option<Vec<TransactionStatus>>,
584
				) {
585
					(
586
						pallet_ethereum::CurrentBlock::<Runtime>::get(),
587
						pallet_ethereum::CurrentReceipts::<Runtime>::get(),
588
						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get(),
589
					)
590
				}
591

            
592
				fn extrinsic_filter(
593
					xts: Vec<<Block as BlockT>::Extrinsic>,
594
				) -> Vec<EthereumTransaction> {
595
					xts.into_iter().filter_map(|xt| match xt.0.function {
596
						RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
597
						_ => None
598
					}).collect::<Vec<EthereumTransaction>>()
599
				}
600

            
601
				fn elasticity() -> Option<Permill> {
602
					None
603
				}
604

            
605
				fn gas_limit_multiplier_support() {}
606

            
607
				fn pending_block(
608
					xts: Vec<<Block as sp_runtime::traits::Block>::Extrinsic>
609
				) -> (
610
					Option<pallet_ethereum::Block>, Option<sp_std::prelude::Vec<TransactionStatus>>
611
				) {
612
					for ext in xts.into_iter() {
613
						let _ = Executive::apply_extrinsic(ext);
614
					}
615

            
616
					Ethereum::on_finalize(System::block_number() + 1);
617

            
618
					(
619
						pallet_ethereum::CurrentBlock::<Runtime>::get(),
620
						pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
621
					)
622
				 }
623

            
624
				fn initialize_pending_block(header: &<Block as BlockT>::Header) {
625
					pallet_randomness::vrf::using_fake_vrf(|| {
626
						let _ = Executive::initialize_block(header);
627
					})
628
				}
629
			}
630

            
631
			impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
632
				fn convert_transaction(
633
					transaction: pallet_ethereum::Transaction
634
				) -> <Block as BlockT>::Extrinsic {
635
					UncheckedExtrinsic::new_unsigned(
636
						pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
637
					)
638
				}
639
			}
640

            
641
			impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
642
			for Runtime {
643
				fn query_info(
644
					uxt: <Block as BlockT>::Extrinsic,
645
					len: u32,
646
				) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
647
					TransactionPayment::query_info(uxt, len)
648
				}
649

            
650
				fn query_fee_details(
651
					uxt: <Block as BlockT>::Extrinsic,
652
					len: u32,
653
				) -> pallet_transaction_payment::FeeDetails<Balance> {
654
					TransactionPayment::query_fee_details(uxt, len)
655
				}
656

            
657
				fn query_weight_to_fee(weight: Weight) -> Balance {
658
					TransactionPayment::weight_to_fee(weight)
659
				}
660

            
661
				fn query_length_to_fee(length: u32) -> Balance {
662
					TransactionPayment::length_to_fee(length)
663
				}
664
			}
665

            
666
			impl nimbus_primitives::NimbusApi<Block> for Runtime {
667
66
				fn can_author(
668
66
					author: nimbus_primitives::NimbusId,
669
66
					slot: u32,
670
66
					parent_header: &<Block as BlockT>::Header
671
66
				) -> bool {
672
66
					use pallet_parachain_staking::Config as PalletParachainStakingConfig;
673
66

            
674
66
					let block_number = parent_header.number + 1;
675
66

            
676
66
					// The Moonbeam runtimes use an entropy source that needs to do some accounting
677
66
					// work during block initialization. Therefore we initialize it here to match
678
66
					// the state it will be in when the next block is being executed.
679
66
					use frame_support::traits::OnInitialize;
680
66
					System::initialize(
681
66
						&block_number,
682
66
						&parent_header.hash(),
683
66
						&parent_header.digest,
684
66
					);
685
66

            
686
66
					// Because the staking solution calculates the next staking set at the beginning
687
66
					// of the first block in the new round, the only way to accurately predict the
688
66
					// authors is to compute the selection during prediction.
689
66
					if pallet_parachain_staking::Pallet::<Self>::round()
690
66
						.should_update(block_number) {
691
						// get author account id
692
						use nimbus_primitives::AccountLookup;
693
						let author_account_id = if let Some(account) =
694
							pallet_author_mapping::Pallet::<Self>::lookup_account(&author) {
695
							account
696
						} else {
697
							// return false if author mapping not registered like in can_author impl
698
							return false
699
						};
700
						let candidates = pallet_parachain_staking::Pallet::<Self>::compute_top_candidates();
701
						if candidates.is_empty() {
702
							// If there are zero selected candidates, we use the same eligibility
703
							// as the previous round
704
							return AuthorInherent::can_author(&author, &slot);
705
						}
706

            
707
						// predict eligibility post-selection by computing selection results now
708
						let (eligible, _) =
709
							pallet_author_slot_filter::compute_pseudo_random_subset::<Self>(
710
								candidates,
711
								&slot
712
							);
713
						eligible.contains(&author_account_id)
714
					} else {
715
66
						AuthorInherent::can_author(&author, &slot)
716
					}
717
				}
718
			}
719

            
720
			impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
721
				fn collect_collation_info(
722
					header: &<Block as BlockT>::Header
723
				) -> cumulus_primitives_core::CollationInfo {
724
					ParachainSystem::collect_collation_info(header)
725
				}
726
			}
727

            
728
			impl session_keys_primitives::VrfApi<Block> for Runtime {
729
				fn get_last_vrf_output() -> Option<<Block as BlockT>::Hash> {
730
					// TODO: remove in future runtime upgrade along with storage item
731
					if pallet_randomness::Pallet::<Self>::not_first_block().is_none() {
732
						return None;
733
					}
734
					pallet_randomness::Pallet::<Self>::local_vrf_output()
735
				}
736
				fn vrf_key_lookup(
737
					nimbus_id: nimbus_primitives::NimbusId
738
				) -> Option<session_keys_primitives::VrfId> {
739
					use session_keys_primitives::KeysLookup;
740
					AuthorMapping::lookup_keys(&nimbus_id)
741
				}
742
			}
743

            
744
			#[cfg(feature = "runtime-benchmarks")]
745
			impl frame_benchmarking::Benchmark<Block> for Runtime {
746

            
747
				fn benchmark_metadata(extra: bool) -> (
748
					Vec<frame_benchmarking::BenchmarkList>,
749
					Vec<frame_support::traits::StorageInfo>,
750
				) {
751
					use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList};
752
					use moonbeam_xcm_benchmarks::generic::benchmarking as MoonbeamXcmBenchmarks;
753
					use frame_support::traits::StorageInfoTrait;
754
					use MoonbeamXcmBenchmarks::XcmGenericBenchmarks as MoonbeamXcmGenericBench;
755

            
756
					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
757

            
758
					let mut list = Vec::<BenchmarkList>::new();
759
					list_benchmarks!(list, extra);
760

            
761
					let storage_info = AllPalletsWithSystem::storage_info();
762

            
763
					return (list, storage_info)
764
				}
765

            
766
				fn dispatch_benchmark(
767
					config: frame_benchmarking::BenchmarkConfig,
768
				) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
769
					use frame_benchmarking::{add_benchmark, BenchmarkBatch, Benchmarking};
770
					use frame_support::traits::TrackedStorageKey;
771
					use cumulus_primitives_core::ParaId;
772

            
773
					use xcm::latest::prelude::{
774
						GeneralIndex, Junction, Junctions, Location, Response, NetworkId, AssetId,
775
						Assets as XcmAssets, Fungible, Asset, ParentThen, Parachain, Parent
776
					};
777
					use xcm_config::SelfReserve;
778
					use frame_benchmarking::BenchmarkError;
779

            
780
					use frame_system_benchmarking::Pallet as SystemBench;
781
					impl frame_system_benchmarking::Config for Runtime {}
782

            
783
					impl moonbeam_xcm_benchmarks::Config for Runtime {}
784
					impl moonbeam_xcm_benchmarks::generic::Config for Runtime {}
785

            
786
					use pallet_asset_manager::Config as PalletAssetManagerConfig;
787

            
788
					use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
789
					parameter_types! {
790
						pub const RandomParaId: ParaId = ParaId::new(43211234);
791
					}
792

            
793
					pub struct TestDeliveryHelper;
794
					impl xcm_builder::EnsureDelivery for TestDeliveryHelper {
795
						fn ensure_successful_delivery(
796
							origin_ref: &Location,
797
							_dest: &Location,
798
							_fee_reason: xcm_executor::traits::FeeReason,
799
						) -> (Option<xcm_executor::FeesMode>, Option<XcmAssets>) {
800
							use xcm_executor::traits::ConvertLocation;
801
							let account = xcm_config::LocationToH160::convert_location(origin_ref)
802
								.expect("Invalid location");
803
							// Give the existential deposit at least
804
							let balance = ExistentialDeposit::get();
805
							let _ = <Balances as frame_support::traits::Currency<_>>::
806
								make_free_balance_be(&account.into(), balance);
807

            
808
							(None, None)
809
						}
810
					}
811

            
812
					impl pallet_xcm::benchmarking::Config for Runtime {
813
				        type DeliveryHelper = TestDeliveryHelper;
814

            
815
						fn get_asset() -> Asset {
816
							Asset {
817
								id: AssetId(SelfReserve::get()),
818
								fun: Fungible(ExistentialDeposit::get()),
819
							}
820
						}
821

            
822
						fn reachable_dest() -> Option<Location> {
823
							Some(Parent.into())
824
						}
825

            
826
						fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
827
							None
828
						}
829

            
830
						fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
831
							use xcm_config::SelfReserve;
832

            
833
							ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
834
								RandomParaId::get().into()
835
							);
836

            
837
							Some((
838
								Asset {
839
									fun: Fungible(ExistentialDeposit::get()),
840
									id: AssetId(SelfReserve::get().into())
841
								},
842
								// Moonbeam can reserve transfer native token to
843
								// some random parachain.
844
								ParentThen(Parachain(RandomParaId::get().into()).into()).into(),
845
							))
846
						}
847

            
848
						fn set_up_complex_asset_transfer(
849
						) -> Option<(XcmAssets, u32, Location, Box<dyn FnOnce()>)> {
850
							use xcm_config::SelfReserve;
851

            
852
							let destination: xcm::v4::Location = Parent.into();
853

            
854
							let fee_amount: u128 = <Runtime as pallet_balances::Config>::ExistentialDeposit::get();
855
							let fee_asset: Asset = (SelfReserve::get(), fee_amount).into();
856

            
857
							// Give some multiple of transferred amount
858
							let balance = fee_amount * 1000;
859
							let who = frame_benchmarking::whitelisted_caller();
860
							let _ =
861
								<Balances as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
862

            
863
							// verify initial balance
864
							assert_eq!(Balances::free_balance(&who), balance);
865

            
866
							// set up local asset
867
							let asset_amount: u128 = 10u128;
868
							let initial_asset_amount: u128 = asset_amount * 10;
869

            
870
							let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::<
871
								Runtime,
872
								()
873
							>(true, initial_asset_amount);
874
							let transfer_asset: Asset = (SelfReserve::get(), asset_amount).into();
875

            
876
							let assets: XcmAssets = vec![fee_asset.clone(), transfer_asset].into();
877
							let fee_index: u32 = 0;
878

            
879
							let verify: Box<dyn FnOnce()> = Box::new(move || {
880
								// verify balance after transfer, decreased by
881
								// transferred amount (and delivery fees)
882
								assert!(Balances::free_balance(&who) <= balance - fee_amount);
883
							});
884

            
885
							Some((assets, fee_index, destination, verify))
886
						}
887
					}
888

            
889
					impl pallet_xcm_benchmarks::Config for Runtime {
890
						type XcmConfig = xcm_config::XcmExecutorConfig;
891
						type AccountIdConverter = xcm_config::LocationToAccountId;
892
						type DeliveryHelper = ();
893
						fn valid_destination() -> Result<Location, BenchmarkError> {
894
							Ok(Location::parent())
895
						}
896
						fn worst_case_holding(_depositable_count: u32) -> XcmAssets {
897
						// 100 fungibles
898
							const HOLDING_FUNGIBLES: u32 = 100;
899
							let fungibles_amount: u128 = 100;
900
							let assets = (0..HOLDING_FUNGIBLES).map(|i| {
901
								let location: Location = GeneralIndex(i as u128).into();
902
								Asset {
903
									id: AssetId(location),
904
									fun: Fungible(fungibles_amount * i as u128),
905
								}
906
								.into()
907
							})
908
							.chain(
909
								core::iter::once(
910
									Asset {
911
										id: AssetId(Location::parent()),
912
										fun: Fungible(u128::MAX)
913
									}
914
								)
915
							)
916
							.collect::<Vec<_>>();
917

            
918

            
919
							for (i, asset) in assets.iter().enumerate() {
920
								if let Asset {
921
									id: AssetId(location),
922
									fun: Fungible(_)
923
								} = asset {
924
									<AssetManager as xcm_primitives::AssetTypeGetter<
925
										<Runtime as PalletAssetManagerConfig>::AssetId,
926
										<Runtime as PalletAssetManagerConfig>::ForeignAssetType>
927
									>::set_asset_type_asset_id(
928
										location.clone().try_into().expect("convert to v3"),
929
										i as u128
930
									);
931
									// set 1-1
932
									<AssetManager as xcm_primitives::UnitsToWeightRatio<
933
										<Runtime as PalletAssetManagerConfig>::ForeignAssetType>
934
									>::set_units_per_second(
935
										location.clone().try_into().expect("convert to v3"),
936
										1_000_000_000_000u128
937
									);
938
								}
939
							}
940
							assets.into()
941
						}
942
					}
943

            
944
					impl pallet_xcm_benchmarks::generic::Config for Runtime {
945
						type RuntimeCall = RuntimeCall;
946
						type TransactAsset = Balances;
947

            
948
						fn worst_case_response() -> (u64, Response) {
949
							(0u64, Response::Version(Default::default()))
950
						}
951

            
952
						fn worst_case_asset_exchange()
953
							-> Result<(XcmAssets, XcmAssets), BenchmarkError> {
954
							Err(BenchmarkError::Skip)
955
						}
956

            
957
						fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
958
							Err(BenchmarkError::Skip)
959
						}
960

            
961
						fn export_message_origin_and_destination()
962
							-> Result<(Location, NetworkId, Junctions), BenchmarkError> {
963
							Err(BenchmarkError::Skip)
964
						}
965

            
966
						fn transact_origin_and_runtime_call()
967
							-> Result<(Location, RuntimeCall), BenchmarkError> {
968
							Ok((Location::parent(), frame_system::Call::remark_with_event {
969
								remark: vec![]
970
							}.into()))
971
						}
972

            
973
						fn subscribe_origin() -> Result<Location, BenchmarkError> {
974
							Ok(Location::parent())
975
						}
976

            
977
						fn claimable_asset()
978
							-> Result<(Location, Location, XcmAssets), BenchmarkError> {
979
							let origin = Location::parent();
980
							let assets: XcmAssets = (AssetId(Location::parent()), 1_000u128)
981
								.into();
982
							let ticket = Location { parents: 0, interior: [].into() /* Here */ };
983
							Ok((origin, ticket, assets))
984
						}
985

            
986
						fn fee_asset() -> Result<Asset, BenchmarkError> {
987
							Err(BenchmarkError::Skip)
988
						}
989

            
990
						fn unlockable_asset()
991
							-> Result<(Location, Location, Asset), BenchmarkError> {
992
							Err(BenchmarkError::Skip)
993
						}
994

            
995
						fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
996
							Err(BenchmarkError::Skip)
997
						}
998
					}
999

            
					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(),
					];
					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")
				}
			}
		}
	};
}