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
//! A collection of node-specific RPC extensions and related background tasks.
18

            
19
pub mod tracing;
20

            
21
use std::{sync::Arc, time::Duration};
22

            
23
use fp_rpc::EthereumRuntimeRPCApi;
24
use sp_block_builder::BlockBuilder;
25

            
26
use crate::client::RuntimeApiCollection;
27
use cumulus_primitives_core::{ParaId, PersistedValidationData};
28
use cumulus_primitives_parachain_inherent::ParachainInherentData;
29
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
30
use fc_mapping_sync::{kv::MappingSyncWorker, SyncStrategy};
31
use fc_rpc::{pending::ConsensusDataProvider, EthBlockDataCacheTask, EthTask, StorageOverride};
32
use fc_rpc_core::types::{FeeHistoryCache, FilterPool, TransactionRequest};
33
use futures::StreamExt;
34
use jsonrpsee::RpcModule;
35
use moonbeam_cli_opt::EthApi as EthApiCmd;
36
use moonbeam_core_primitives::{Block, Hash};
37
use sc_client_api::{
38
	backend::{AuxStore, Backend, StateBackend, StorageProvider},
39
	client::BlockchainEvents,
40
	BlockOf,
41
};
42
use sc_consensus_manual_seal::rpc::{EngineCommand, ManualSeal, ManualSealApiServer};
43
use sc_network::service::traits::NetworkService;
44
use sc_network_sync::SyncingService;
45
use sc_rpc::SubscriptionTaskExecutor;
46
use sc_rpc_api::DenyUnsafe;
47
use sc_service::TaskManager;
48
use sc_transaction_pool::{ChainApi, Pool};
49
use sc_transaction_pool_api::TransactionPool;
50
use sp_api::{CallApiAt, ProvideRuntimeApi};
51
use sp_blockchain::{
52
	Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata,
53
};
54
use sp_core::H256;
55
use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Header as HeaderT};
56
use std::collections::BTreeMap;
57

            
58
pub struct MoonbeamEGA;
59

            
60
impl fc_rpc::EstimateGasAdapter for MoonbeamEGA {
61
8008
	fn adapt_request(mut request: TransactionRequest) -> TransactionRequest {
62
8008
		// Redirect any call to batch precompile:
63
8008
		// force usage of batchAll method for estimation
64
8008
		use sp_core::H160;
65
8008
		const BATCH_PRECOMPILE_ADDRESS: H160 = H160(hex_literal::hex!(
66
8008
			"0000000000000000000000000000000000000808"
67
8008
		));
68
8008
		const BATCH_PRECOMPILE_BATCH_ALL_SELECTOR: [u8; 4] = hex_literal::hex!("96e292b8");
69
8008
		if request.to == Some(BATCH_PRECOMPILE_ADDRESS) {
70
18
			match (&mut request.data.input, &mut request.data.data) {
71
				(Some(ref mut input), _) => {
72
					if input.0.len() >= 4 {
73
						input.0[..4].copy_from_slice(&BATCH_PRECOMPILE_BATCH_ALL_SELECTOR);
74
					}
75
				}
76
18
				(None, Some(ref mut data)) => {
77
18
					if data.0.len() >= 4 {
78
18
						data.0[..4].copy_from_slice(&BATCH_PRECOMPILE_BATCH_ALL_SELECTOR);
79
18
					}
80
				}
81
				(_, _) => {}
82
			};
83
7990
		}
84
8008
		request
85
8008
	}
86
}
87

            
88
pub struct MoonbeamEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
89

            
90
impl<C, BE> fc_rpc::EthConfig<Block, C> for MoonbeamEthConfig<C, BE>
91
where
92
	C: sc_client_api::StorageProvider<Block, BE> + Sync + Send + 'static,
93
	BE: Backend<Block> + 'static,
94
{
95
	type EstimateGasAdapter = MoonbeamEGA;
96
	type RuntimeStorageOverride =
97
		fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
98
}
99

            
100
/// Full client dependencies.
101
pub struct FullDeps<C, P, A: ChainApi, BE> {
102
	/// The client instance to use.
103
	pub client: Arc<C>,
104
	/// Transaction pool instance.
105
	pub pool: Arc<P>,
106
	/// Graph pool instance.
107
	pub graph: Arc<Pool<A>>,
108
	/// Whether to deny unsafe calls
109
	pub deny_unsafe: DenyUnsafe,
110
	/// The Node authority flag
111
	pub is_authority: bool,
112
	/// Network service
113
	pub network: Arc<dyn NetworkService>,
114
	/// Chain syncing service
115
	pub sync: Arc<SyncingService<Block>>,
116
	/// EthFilterApi pool.
117
	pub filter_pool: Option<FilterPool>,
118
	/// The list of optional RPC extensions.
119
	pub ethapi_cmd: Vec<EthApiCmd>,
120
	/// Frontier Backend.
121
	pub frontier_backend: Arc<dyn fc_api::Backend<Block>>,
122
	/// Backend.
123
	pub backend: Arc<BE>,
124
	/// Manual seal command sink
125
	pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
126
	/// Maximum number of logs in a query.
127
	pub max_past_logs: u32,
128
	/// Maximum fee history cache size.
129
	pub fee_history_limit: u64,
130
	/// Fee history cache.
131
	pub fee_history_cache: FeeHistoryCache,
132
	/// Channels for manual xcm messages (downward, hrmp)
133
	pub dev_rpc_data: Option<(
134
		flume::Sender<Vec<u8>>,
135
		flume::Sender<(ParaId, Vec<u8>)>,
136
		Arc<std::sync::atomic::AtomicU32>,
137
	)>,
138
	/// Ethereum data access overrides.
139
	pub overrides: Arc<dyn StorageOverride<Block>>,
140
	/// Cache for Ethereum block data.
141
	pub block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
142
	/// Mandated parent hashes for a given block hash.
143
	pub forced_parent_hashes: Option<BTreeMap<H256, H256>>,
144
}
145

            
146
pub struct TracingConfig {
147
	pub tracing_requesters: crate::rpc::tracing::RpcRequesters,
148
	pub trace_filter_max_count: u32,
149
}
150

            
151
/// Instantiate all Full RPC extensions.
152
1784
pub fn create_full<C, P, BE, A>(
153
1784
	deps: FullDeps<C, P, A, BE>,
154
1784
	subscription_task_executor: SubscriptionTaskExecutor,
155
1784
	maybe_tracing_config: Option<TracingConfig>,
156
1784
	pubsub_notification_sinks: Arc<
157
1784
		fc_mapping_sync::EthereumBlockNotificationSinks<
158
1784
			fc_mapping_sync::EthereumBlockNotification<Block>,
159
1784
		>,
160
1784
	>,
161
1784
	pending_consenus_data_provider: Box<dyn ConsensusDataProvider<Block>>,
162
1784
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
163
1784
where
164
1784
	BE: Backend<Block> + 'static,
165
1784
	BE::State: StateBackend<BlakeTwo256>,
166
1784
	BE::Blockchain: BlockchainBackend<Block>,
167
1784
	C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
168
1784
	C: BlockchainEvents<Block>,
169
1784
	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
170
1784
	C: CallApiAt<Block>,
171
1784
	C: Send + Sync + 'static,
172
1784
	A: ChainApi<Block = Block> + 'static,
173
1784
	C::Api: RuntimeApiCollection,
174
1784
	P: TransactionPool<Block = Block> + 'static,
175
1784
{
176
1784
	use fc_rpc::{
177
1784
		Eth, EthApiServer, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, Net,
178
1784
		NetApiServer, Web3, Web3ApiServer,
179
1784
	};
180
1784
	use moonbeam_dev_rpc::{DevApiServer, DevRpc};
181
1784
	use moonbeam_finality_rpc::{MoonbeamFinality, MoonbeamFinalityApiServer};
182
1784
	use moonbeam_rpc_debug::{Debug, DebugServer};
183
1784
	use moonbeam_rpc_trace::{Trace, TraceServer};
184
1784
	use moonbeam_rpc_txpool::{TxPool, TxPoolServer};
185
1784
	use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
186
1784
	use substrate_frame_rpc_system::{System, SystemApiServer};
187
1784

            
188
1784
	let mut io = RpcModule::new(());
189
1784
	let FullDeps {
190
1784
		client,
191
1784
		pool,
192
1784
		graph,
193
1784
		deny_unsafe,
194
1784
		is_authority,
195
1784
		network,
196
1784
		sync,
197
1784
		filter_pool,
198
1784
		ethapi_cmd,
199
1784
		command_sink,
200
1784
		frontier_backend,
201
1784
		backend: _,
202
1784
		max_past_logs,
203
1784
		fee_history_limit,
204
1784
		fee_history_cache,
205
1784
		dev_rpc_data,
206
1784
		overrides,
207
1784
		block_data_cache,
208
1784
		forced_parent_hashes,
209
1784
	} = deps;
210
1784

            
211
1784
	io.merge(System::new(Arc::clone(&client), Arc::clone(&pool), deny_unsafe).into_rpc())?;
212
1784
	io.merge(TransactionPayment::new(Arc::clone(&client)).into_rpc())?;
213

            
214
	// TODO: are we supporting signing?
215
1784
	let signers = Vec::new();
216
1784

            
217
1784
	enum Never {}
218
1784
	impl<T> fp_rpc::ConvertTransaction<T> for Never {
219
1784
		fn convert_transaction(&self, _transaction: pallet_ethereum::Transaction) -> T {
220
			// The Never type is not instantiable, but this method requires the type to be
221
			// instantiated to be called (`&self` parameter), so if the code compiles we have the
222
			// guarantee that this function will never be called.
223
			unreachable!()
224
1784
		}
225
1784
	}
226
1784
	let convert_transaction: Option<Never> = None;
227
1784

            
228
1784
	let pending_create_inherent_data_providers = move |_, _| async move {
229
8
		let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
230
8
		// Create a dummy parachain inherent data provider which is required to pass
231
8
		// the checks by the para chain system. We use dummy values because in the 'pending context'
232
8
		// neither do we have access to the real values nor do we need them.
233
8
		let (relay_parent_storage_root, relay_chain_state) =
234
8
			RelayStateSproofBuilder::default().into_state_root_and_proof();
235
8
		let vfp = PersistedValidationData {
236
8
			// This is a hack to make `cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases`
237
8
			// happy. Relay parent number can't be bigger than u32::MAX.
238
8
			relay_parent_number: u32::MAX,
239
8
			relay_parent_storage_root,
240
8
			..Default::default()
241
8
		};
242
8
		let parachain_inherent_data = ParachainInherentData {
243
8
			validation_data: vfp,
244
8
			relay_chain_state,
245
8
			downward_messages: Default::default(),
246
8
			horizontal_messages: Default::default(),
247
8
		};
248
8
		Ok((timestamp, parachain_inherent_data))
249
8
	};
250

            
251
1784
	io.merge(
252
1784
		Eth::<_, _, _, _, _, _, _, MoonbeamEthConfig<_, _>>::new(
253
1784
			Arc::clone(&client),
254
1784
			Arc::clone(&pool),
255
1784
			graph.clone(),
256
1784
			convert_transaction,
257
1784
			Arc::clone(&sync),
258
1784
			signers,
259
1784
			Arc::clone(&overrides),
260
1784
			Arc::clone(&frontier_backend),
261
1784
			is_authority,
262
1784
			Arc::clone(&block_data_cache),
263
1784
			fee_history_cache,
264
1784
			fee_history_limit,
265
1784
			10,
266
1784
			forced_parent_hashes,
267
1784
			pending_create_inherent_data_providers,
268
1784
			Some(pending_consenus_data_provider),
269
1784
		)
270
1784
		.replace_config::<MoonbeamEthConfig<C, BE>>()
271
1784
		.into_rpc(),
272
1784
	)?;
273

            
274
1784
	if let Some(filter_pool) = filter_pool {
275
1784
		io.merge(
276
1784
			EthFilter::new(
277
1784
				client.clone(),
278
1784
				frontier_backend.clone(),
279
1784
				graph.clone(),
280
1784
				filter_pool,
281
1784
				500_usize, // max stored filters
282
1784
				max_past_logs,
283
1784
				block_data_cache,
284
1784
			)
285
1784
			.into_rpc(),
286
1784
		)?;
287
	}
288

            
289
1784
	io.merge(
290
1784
		Net::new(
291
1784
			Arc::clone(&client),
292
1784
			network.clone(),
293
1784
			// Whether to format the `peer_count` response as Hex (default) or not.
294
1784
			true,
295
1784
		)
296
1784
		.into_rpc(),
297
1784
	)?;
298

            
299
1784
	io.merge(Web3::new(Arc::clone(&client)).into_rpc())?;
300
1784
	io.merge(
301
1784
		EthPubSub::new(
302
1784
			pool,
303
1784
			Arc::clone(&client),
304
1784
			sync.clone(),
305
1784
			subscription_task_executor,
306
1784
			overrides,
307
1784
			pubsub_notification_sinks.clone(),
308
1784
		)
309
1784
		.into_rpc(),
310
1784
	)?;
311
1784
	if ethapi_cmd.contains(&EthApiCmd::Txpool) {
312
1784
		io.merge(TxPool::new(Arc::clone(&client), graph).into_rpc())?;
313
	}
314

            
315
1784
	io.merge(MoonbeamFinality::new(client.clone(), frontier_backend.clone()).into_rpc())?;
316

            
317
1784
	if let Some(command_sink) = command_sink {
318
1784
		io.merge(
319
1784
			// We provide the rpc handler with the sending end of the channel to allow the rpc
320
1784
			// send EngineCommands to the background block authorship task.
321
1784
			ManualSeal::new(command_sink).into_rpc(),
322
1784
		)?;
323
	};
324

            
325
1784
	if let Some((downward_message_channel, hrmp_message_channel, additional_relay_offset)) =
326
1784
		dev_rpc_data
327
	{
328
1784
		io.merge(
329
1784
			DevRpc {
330
1784
				downward_message_channel,
331
1784
				hrmp_message_channel,
332
1784
				additional_relay_offset,
333
1784
			}
334
1784
			.into_rpc(),
335
1784
		)?;
336
	}
337

            
338
1784
	if let Some(tracing_config) = maybe_tracing_config {
339
		if let Some(trace_filter_requester) = tracing_config.tracing_requesters.trace {
340
			io.merge(
341
				Trace::new(
342
					client,
343
					trace_filter_requester,
344
					tracing_config.trace_filter_max_count,
345
				)
346
				.into_rpc(),
347
			)?;
348
		}
349

            
350
		if let Some(debug_requester) = tracing_config.tracing_requesters.debug {
351
			io.merge(Debug::new(debug_requester).into_rpc())?;
352
		}
353
1784
	}
354

            
355
1784
	Ok(io)
356
1784
}
357

            
358
pub struct SpawnTasksParams<'a, B: BlockT, C, BE> {
359
	pub task_manager: &'a TaskManager,
360
	pub client: Arc<C>,
361
	pub substrate_backend: Arc<BE>,
362
	pub frontier_backend: Arc<fc_db::Backend<B, C>>,
363
	pub filter_pool: Option<FilterPool>,
364
	pub overrides: Arc<dyn StorageOverride<B>>,
365
	pub fee_history_limit: u64,
366
	pub fee_history_cache: FeeHistoryCache,
367
}
368

            
369
/// Spawn the tasks that are required to run Moonbeam.
370
892
pub fn spawn_essential_tasks<B, C, BE>(
371
892
	params: SpawnTasksParams<B, C, BE>,
372
892
	sync: Arc<SyncingService<B>>,
373
892
	pubsub_notification_sinks: Arc<
374
892
		fc_mapping_sync::EthereumBlockNotificationSinks<
375
892
			fc_mapping_sync::EthereumBlockNotification<B>,
376
892
		>,
377
892
	>,
378
892
) where
379
892
	C: ProvideRuntimeApi<B> + BlockOf,
380
892
	C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
381
892
	C: BlockchainEvents<B> + StorageProvider<B, BE>,
382
892
	C: Send + Sync + 'static,
383
892
	C::Api: EthereumRuntimeRPCApi<B>,
384
892
	C::Api: BlockBuilder<B>,
385
892
	B: BlockT<Hash = H256> + Send + Sync + 'static,
386
892
	B::Header: HeaderT<Number = u32>,
387
892
	BE: Backend<B> + 'static,
388
892
	BE::State: StateBackend<BlakeTwo256>,
389
892
{
390
892
	// Frontier offchain DB task. Essential.
391
892
	// Maps emulated ethereum data to substrate native data.
392
892
	match *params.frontier_backend {
393
892
		fc_db::Backend::KeyValue(ref b) => {
394
892
			params.task_manager.spawn_essential_handle().spawn(
395
892
				"frontier-mapping-sync-worker",
396
892
				Some("frontier"),
397
892
				MappingSyncWorker::new(
398
892
					params.client.import_notification_stream(),
399
892
					Duration::new(6, 0),
400
892
					params.client.clone(),
401
892
					params.substrate_backend.clone(),
402
892
					params.overrides.clone(),
403
892
					b.clone(),
404
892
					3,
405
892
					0,
406
892
					SyncStrategy::Parachain,
407
892
					sync.clone(),
408
892
					pubsub_notification_sinks.clone(),
409
892
				)
410
48588
				.for_each(|()| futures::future::ready(())),
411
892
			);
412
892
		}
413
		fc_db::Backend::Sql(ref b) => {
414
			params.task_manager.spawn_essential_handle().spawn_blocking(
415
				"frontier-mapping-sync-worker",
416
				Some("frontier"),
417
				fc_mapping_sync::sql::SyncWorker::run(
418
					params.client.clone(),
419
					params.substrate_backend.clone(),
420
					b.clone(),
421
					params.client.import_notification_stream(),
422
					fc_mapping_sync::sql::SyncWorkerConfig {
423
						read_notification_timeout: Duration::from_secs(10),
424
						check_indexed_blocks_interval: Duration::from_secs(60),
425
					},
426
					fc_mapping_sync::SyncStrategy::Parachain,
427
					sync.clone(),
428
					pubsub_notification_sinks.clone(),
429
				),
430
			);
431
		}
432
	}
433

            
434
	// Frontier `EthFilterApi` maintenance.
435
	// Manages the pool of user-created Filters.
436
892
	if let Some(filter_pool) = params.filter_pool {
437
892
		// Each filter is allowed to stay in the pool for 100 blocks.
438
892
		const FILTER_RETAIN_THRESHOLD: u64 = 100;
439
892
		params.task_manager.spawn_essential_handle().spawn(
440
892
			"frontier-filter-pool",
441
892
			Some("frontier"),
442
892
			EthTask::filter_pool_task(
443
892
				Arc::clone(&params.client),
444
892
				filter_pool,
445
892
				FILTER_RETAIN_THRESHOLD,
446
892
			),
447
892
		);
448
892
	}
449

            
450
	// Spawn Frontier FeeHistory cache maintenance task.
451
892
	params.task_manager.spawn_essential_handle().spawn(
452
892
		"frontier-fee-history",
453
892
		Some("frontier"),
454
892
		EthTask::fee_history_task(
455
892
			Arc::clone(&params.client),
456
892
			Arc::clone(&params.overrides),
457
892
			params.fee_history_cache,
458
892
			params.fee_history_limit,
459
892
		),
460
892
	);
461
892
}