lib.rs 14.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

17
18
19
20
//! Polkadot Client
//!
//! Provides the [`AbstractClient`] trait that is a super trait that combines all the traits the client implements.
//! There is also the [`Client`] enum that combines all the different clients into one common structure.
21

Shawn Tabrizi's avatar
Shawn Tabrizi committed
22
23
24
25
26
use polkadot_primitives::v1::{
	AccountId, Balance, Block, BlockNumber, Hash, Header, Nonce, ParachainHost,
};
use sc_client_api::{AuxStore, Backend as BackendT, BlockchainEvents, KeyIterator, UsageProvider};
use sp_api::{CallApiAt, NumberFor, ProvideRuntimeApi};
27
use sp_blockchain::HeaderBackend;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
28
use sp_consensus::BlockStatus;
29
use sp_runtime::{
Shawn Tabrizi's avatar
Shawn Tabrizi committed
30
31
32
	generic::{BlockId, SignedBlock},
	traits::{BlakeTwo256, Block as BlockT},
	Justifications,
33
};
Shawn Tabrizi's avatar
Shawn Tabrizi committed
34
35
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
use std::sync::Arc;
36
37
38
39
40

pub type FullBackend = sc_service::TFullBackend<Block>;

pub type FullClient<RuntimeApi, Executor> = sc_service::TFullClient<Block, RuntimeApi, Executor>;

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/// The native executor instance for Polkadot.
pub struct PolkadotExecutor;

impl sc_executor::NativeExecutionDispatch for PolkadotExecutor {
	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;

	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
		polkadot_runtime::api::dispatch(method, data)
	}

	fn native_version() -> sc_executor::NativeVersion {
		polkadot_runtime::native_version()
	}
}

#[cfg(feature = "kusama")]
/// The native executor instance for Kusama.
pub struct KusamaExecutor;
59
60

#[cfg(feature = "kusama")]
61
62
63
64
65
66
67
68
69
70
71
impl sc_executor::NativeExecutionDispatch for KusamaExecutor {
	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;

	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
		kusama_runtime::api::dispatch(method, data)
	}

	fn native_version() -> sc_executor::NativeVersion {
		kusama_runtime::native_version()
	}
}
72
73

#[cfg(feature = "westend")]
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/// The native executor instance for Westend.
pub struct WestendExecutor;

#[cfg(feature = "westend")]
impl sc_executor::NativeExecutionDispatch for WestendExecutor {
	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;

	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
		westend_runtime::api::dispatch(method, data)
	}

	fn native_version() -> sc_executor::NativeVersion {
		westend_runtime::native_version()
	}
}
89
90

#[cfg(feature = "rococo")]
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/// The native executor instance for Rococo.
pub struct RococoExecutor;

#[cfg(feature = "rococo")]
impl sc_executor::NativeExecutionDispatch for RococoExecutor {
	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;

	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
		rococo_runtime::api::dispatch(method, data)
	}

	fn native_version() -> sc_executor::NativeVersion {
		rococo_runtime::native_version()
	}
}
106

107
108
109
/// A set of APIs that polkadot-like runtimes must implement.
pub trait RuntimeApiCollection:
	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
110
	+ sp_api::ApiExt<Block>
111
	+ sp_consensus_babe::BabeApi<Block>
112
	+ sp_finality_grandpa::GrandpaApi<Block>
113
114
115
	+ ParachainHost<Block>
	+ sp_block_builder::BlockBuilder<Block>
	+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
116
	+ pallet_mmr_primitives::MmrApi<Block, <Block as BlockT>::Hash>
117
118
119
120
	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
	+ sp_api::Metadata<Block>
	+ sp_offchain::OffchainWorkerApi<Block>
	+ sp_session::SessionKeys<Block>
121
	+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
Andreas Doerr's avatar
Andreas Doerr committed
122
	+ beefy_primitives::BeefyApi<Block>
123
124
where
	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
125
126
{
}
127
128
129
130

impl<Api> RuntimeApiCollection for Api
where
	Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
131
		+ sp_api::ApiExt<Block>
132
		+ sp_consensus_babe::BabeApi<Block>
133
		+ sp_finality_grandpa::GrandpaApi<Block>
134
135
136
		+ ParachainHost<Block>
		+ sp_block_builder::BlockBuilder<Block>
		+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
137
		+ pallet_mmr_primitives::MmrApi<Block, <Block as BlockT>::Hash>
138
139
140
141
		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
		+ sp_api::Metadata<Block>
		+ sp_offchain::OffchainWorkerApi<Block>
		+ sp_session::SessionKeys<Block>
142
		+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
Andreas Doerr's avatar
Andreas Doerr committed
143
		+ beefy_primitives::BeefyApi<Block>,
144
	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
145
146
{
}
147
148
149
150
151

/// Trait that abstracts over all available client implementations.
///
/// For a concrete type there exists [`Client`].
pub trait AbstractClient<Block, Backend>:
Shawn Tabrizi's avatar
Shawn Tabrizi committed
152
153
154
155
	BlockchainEvents<Block>
	+ Sized
	+ Send
	+ Sync
156
	+ ProvideRuntimeApi<Block>
157
	+ HeaderBackend<Block>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
158
	+ CallApiAt<Block, StateBackend = Backend::State>
159
	+ AuxStore
160
	+ UsageProvider<Block>
Shawn Tabrizi's avatar
Shawn Tabrizi committed
161
162
163
164
165
166
167
where
	Block: BlockT,
	Backend: BackendT<Block>,
	Backend::State: sp_api::StateBackend<BlakeTwo256>,
	Self::Api: RuntimeApiCollection<StateBackend = Backend::State>,
{
}
168

169
impl<Block, Backend, Client> AbstractClient<Block, Backend> for Client
Shawn Tabrizi's avatar
Shawn Tabrizi committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
where
	Block: BlockT,
	Backend: BackendT<Block>,
	Backend::State: sp_api::StateBackend<BlakeTwo256>,
	Client: BlockchainEvents<Block>
		+ ProvideRuntimeApi<Block>
		+ HeaderBackend<Block>
		+ AuxStore
		+ UsageProvider<Block>
		+ Sized
		+ Send
		+ Sync
		+ CallApiAt<Block, StateBackend = Backend::State>,
	Client::Api: RuntimeApiCollection<StateBackend = Backend::State>,
{
}
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

/// Execute something with the client instance.
///
/// As there exist multiple chains inside Polkadot, like Polkadot itself, Kusama, Westend etc,
/// there can exist different kinds of client types. As these client types differ in the generics
/// that are being used, we can not easily return them from a function. For returning them from a
/// function there exists [`Client`]. However, the problem on how to use this client instance still
/// exists. This trait "solves" it in a dirty way. It requires a type to implement this trait and
/// than the [`execute_with_client`](ExecuteWithClient::execute_with_client) function can be called
/// with any possible client instance.
///
/// In a perfect world, we could make a closure work in this way.
pub trait ExecuteWithClient {
	/// The return type when calling this instance.
	type Output;

	/// Execute whatever should be executed with the given client instance.
	fn execute_with_client<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
Shawn Tabrizi's avatar
Shawn Tabrizi committed
204
205
206
207
208
209
	where
		<Api as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
		Backend: sc_client_api::Backend<Block> + 'static,
		Backend::State: sp_api::StateBackend<BlakeTwo256>,
		Api: crate::RuntimeApiCollection<StateBackend = Backend::State>,
		Client: AbstractClient<Block, Backend, Api = Api> + 'static;
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
}

/// A handle to a Polkadot client instance.
///
/// The Polkadot service supports multiple different runtimes (Westend, Polkadot itself, etc). As each runtime has a
/// specialized client, we need to hide them behind a trait. This is this trait.
///
/// When wanting to work with the inner client, you need to use `execute_with`.
///
/// See [`ExecuteWithClient`](trait.ExecuteWithClient.html) for more information.
pub trait ClientHandle {
	/// Execute the given something with the client.
	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output;
}

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
macro_rules! with_client {
	{
		$self:ident,
		$client:ident,
		{
			$( $code:tt )*
		}
	} => {
		match $self {
			Self::Polkadot($client) => { $( $code )* },
			#[cfg(feature = "westend")]
			Self::Westend($client) => { $( $code )* },
			#[cfg(feature = "kusama")]
			Self::Kusama($client) => { $( $code )* },
			#[cfg(feature = "rococo")]
			Self::Rococo($client) => { $( $code )* },
		}
	}
}

245
246
247
248
249
/// A client instance of Polkadot.
///
/// See [`ExecuteWithClient`] for more information.
#[derive(Clone)]
pub enum Client {
250
251
252
253
254
255
256
	Polkadot(Arc<FullClient<polkadot_runtime::RuntimeApi, PolkadotExecutor>>),
	#[cfg(feature = "westend")]
	Westend(Arc<FullClient<westend_runtime::RuntimeApi, WestendExecutor>>),
	#[cfg(feature = "kusama")]
	Kusama(Arc<FullClient<kusama_runtime::RuntimeApi, KusamaExecutor>>),
	#[cfg(feature = "rococo")]
	Rococo(Arc<FullClient<rococo_runtime::RuntimeApi, RococoExecutor>>),
257
258
259
260
}

impl ClientHandle for Client {
	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output {
261
262
263
264
265
		with_client! {
			self,
			client,
			{
				T::execute_with_client::<_, _, FullBackend>(t, client.clone())
266
			}
267
268
269
270
		}
	}
}

271
impl UsageProvider<Block> for Client {
272
	fn usage_info(&self) -> sc_client_api::ClientInfo<Block> {
273
274
275
276
277
278
		with_client! {
			self,
			client,
			{
				client.usage_info()
			}
279
280
281
282
283
284
285
		}
	}
}

impl sc_client_api::BlockBackend<Block> for Client {
	fn block_body(
		&self,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
286
		id: &BlockId<Block>,
287
	) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
288
289
290
291
292
293
		with_client! {
			self,
			client,
			{
				client.block_body(id)
			}
294
295
296
297
		}
	}

	fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>> {
298
299
300
301
302
303
		with_client! {
			self,
			client,
			{
				client.block(id)
			}
304
305
306
307
		}
	}

	fn block_status(&self, id: &BlockId<Block>) -> sp_blockchain::Result<BlockStatus> {
308
309
310
311
312
313
		with_client! {
			self,
			client,
			{
				client.block_status(id)
			}
314
315
316
		}
	}

Shawn Tabrizi's avatar
Shawn Tabrizi committed
317
	fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> {
318
319
320
321
322
323
		with_client! {
			self,
			client,
			{
				client.justifications(id)
			}
324
325
326
327
328
		}
	}

	fn block_hash(
		&self,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
329
		number: NumberFor<Block>,
330
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
331
332
333
334
335
336
		with_client! {
			self,
			client,
			{
				client.block_hash(number)
			}
337
338
		}
	}
339

340
	fn indexed_transaction(
341
		&self,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
342
		id: &<Block as BlockT>::Hash,
343
	) -> sp_blockchain::Result<Option<Vec<u8>>> {
344
345
346
347
348
349
		with_client! {
			self,
			client,
			{
				client.indexed_transaction(id)
			}
350
351
352
		}
	}

353
354
	fn block_indexed_body(
		&self,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
355
		id: &BlockId<Block>,
356
	) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
357
358
359
360
361
362
		with_client! {
			self,
			client,
			{
				client.block_indexed_body(id)
			}
363
364
		}
	}
365
366
367
368
369
370
371
372
}

impl sc_client_api::StorageProvider<Block, crate::FullBackend> for Client {
	fn storage(
		&self,
		id: &BlockId<Block>,
		key: &StorageKey,
	) -> sp_blockchain::Result<Option<StorageData>> {
373
374
375
376
377
378
		with_client! {
			self,
			client,
			{
				client.storage(id, key)
			}
379
380
381
382
383
384
385
386
		}
	}

	fn storage_keys(
		&self,
		id: &BlockId<Block>,
		key_prefix: &StorageKey,
	) -> sp_blockchain::Result<Vec<StorageKey>> {
387
388
389
390
391
392
		with_client! {
			self,
			client,
			{
				client.storage_keys(id, key_prefix)
			}
393
394
395
396
397
398
399
400
		}
	}

	fn storage_hash(
		&self,
		id: &BlockId<Block>,
		key: &StorageKey,
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
401
402
403
404
405
406
		with_client! {
			self,
			client,
			{
				client.storage_hash(id, key)
			}
407
408
409
410
411
412
413
414
		}
	}

	fn storage_pairs(
		&self,
		id: &BlockId<Block>,
		key_prefix: &StorageKey,
	) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>> {
415
416
417
418
419
420
		with_client! {
			self,
			client,
			{
				client.storage_pairs(id, key_prefix)
			}
421
422
423
424
425
426
427
428
		}
	}

	fn storage_keys_iter<'a>(
		&self,
		id: &BlockId<Block>,
		prefix: Option<&'a StorageKey>,
		start_key: Option<&StorageKey>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
429
430
431
	) -> sp_blockchain::Result<
		KeyIterator<'a, <crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
	> {
432
433
434
435
436
437
		with_client! {
			self,
			client,
			{
				client.storage_keys_iter(id, prefix, start_key)
			}
438
439
440
441
442
443
444
445
446
		}
	}

	fn child_storage(
		&self,
		id: &BlockId<Block>,
		child_info: &ChildInfo,
		key: &StorageKey,
	) -> sp_blockchain::Result<Option<StorageData>> {
447
448
449
450
451
452
		with_client! {
			self,
			client,
			{
				client.child_storage(id, child_info, key)
			}
453
454
455
456
457
458
459
460
461
		}
	}

	fn child_storage_keys(
		&self,
		id: &BlockId<Block>,
		child_info: &ChildInfo,
		key_prefix: &StorageKey,
	) -> sp_blockchain::Result<Vec<StorageKey>> {
462
463
464
465
466
467
		with_client! {
			self,
			client,
			{
				client.child_storage_keys(id, child_info, key_prefix)
			}
468
469
470
		}
	}

471
472
473
474
475
476
	fn child_storage_keys_iter<'a>(
		&self,
		id: &BlockId<Block>,
		child_info: ChildInfo,
		prefix: Option<&'a StorageKey>,
		start_key: Option<&StorageKey>,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
477
478
479
	) -> sp_blockchain::Result<
		KeyIterator<'a, <crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
	> {
480
481
482
483
484
485
486
487
488
		with_client! {
			self,
			client,
			{
				client.child_storage_keys_iter(id, child_info, prefix, start_key)
			}
		}
	}

489
490
491
492
493
494
	fn child_storage_hash(
		&self,
		id: &BlockId<Block>,
		child_info: &ChildInfo,
		key: &StorageKey,
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
495
496
497
498
499
500
		with_client! {
			self,
			client,
			{
				client.child_storage_hash(id, child_info, key)
			}
501
502
503
504
505
506
507
508
		}
	}

	fn max_key_changes_range(
		&self,
		first: NumberFor<Block>,
		last: BlockId<Block>,
	) -> sp_blockchain::Result<Option<(NumberFor<Block>, BlockId<Block>)>> {
509
510
511
512
513
514
		with_client! {
			self,
			client,
			{
				client.max_key_changes_range(first, last)
			}
515
516
517
518
519
520
521
522
523
524
		}
	}

	fn key_changes(
		&self,
		first: NumberFor<Block>,
		last: BlockId<Block>,
		storage_key: Option<&PrefixedStorageKey>,
		key: &StorageKey,
	) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>> {
525
526
527
528
529
530
		with_client! {
			self,
			client,
			{
				client.key_changes(first, last, storage_key, key)
			}
531
532
533
534
535
536
		}
	}
}

impl sp_blockchain::HeaderBackend<Block> for Client {
	fn header(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Header>> {
537
538
539
540
541
542
		with_client! {
			self,
			client,
			{
				client.header(&id)
			}
543
544
545
546
		}
	}

	fn info(&self) -> sp_blockchain::Info<Block> {
547
548
549
550
551
552
		with_client! {
			self,
			client,
			{
				client.info()
			}
553
554
555
556
		}
	}

	fn status(&self, id: BlockId<Block>) -> sp_blockchain::Result<sp_blockchain::BlockStatus> {
557
558
559
560
561
562
		with_client! {
			self,
			client,
			{
				client.status(id)
			}
563
564
565
566
		}
	}

	fn number(&self, hash: Hash) -> sp_blockchain::Result<Option<BlockNumber>> {
567
568
569
570
571
572
		with_client! {
			self,
			client,
			{
				client.number(hash)
			}
573
574
575
576
		}
	}

	fn hash(&self, number: BlockNumber) -> sp_blockchain::Result<Option<Hash>> {
577
578
579
580
581
582
		with_client! {
			self,
			client,
			{
				client.hash(number)
			}
583
584
585
		}
	}
}