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
pub use moonbeam_core_primitives::{AccountId, Balance, Block, BlockNumber, Hash, Header, Index};
17
use sc_client_api::{Backend as BackendT, BlockchainEvents, KeysIter, MerkleValue, PairsIter};
18
use sp_api::{CallApiAt, ProvideRuntimeApi};
19
use sp_blockchain::HeaderBackend;
20
use sp_consensus::BlockStatus;
21
use sp_runtime::{
22
	generic::SignedBlock,
23
	traits::{BlakeTwo256, Block as BlockT, NumberFor},
24
	Justifications,
25
};
26
use sp_storage::{ChildInfo, StorageData, StorageKey};
27
use std::sync::Arc;
28

            
29
/// A set of APIs that polkadot-like runtimes must implement.
30
///
31
/// This trait has no methods or associated type. It is a concise marker for all the trait bounds
32
/// that it contains.
33
pub trait RuntimeApiCollection:
34
	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
35
	+ sp_api::ApiExt<Block>
36
	+ sp_block_builder::BlockBuilder<Block>
37
	+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
38
	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
39
	+ sp_api::Metadata<Block>
40
	+ sp_offchain::OffchainWorkerApi<Block>
41
	+ sp_session::SessionKeys<Block>
42
	+ fp_rpc::ConvertTransactionRuntimeApi<Block>
43
	+ fp_rpc::EthereumRuntimeRPCApi<Block>
44
	+ moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block>
45
	+ moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block>
46
	+ nimbus_primitives::NimbusApi<Block>
47
	+ cumulus_primitives_core::CollectCollationInfo<Block>
48
	+ session_keys_primitives::VrfApi<Block>
49
	+ async_backing_primitives::UnincludedSegmentApi<Block>
50
	+ xcm_runtime_apis::fees::XcmPaymentApi<Block>
51
{
52
}
53

            
54
impl<Api> RuntimeApiCollection for Api where
55
	Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
56
		+ sp_api::ApiExt<Block>
57
		+ sp_block_builder::BlockBuilder<Block>
58
		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
59
		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
60
		+ sp_api::Metadata<Block>
61
		+ sp_offchain::OffchainWorkerApi<Block>
62
		+ sp_session::SessionKeys<Block>
63
		+ fp_rpc::ConvertTransactionRuntimeApi<Block>
64
		+ fp_rpc::EthereumRuntimeRPCApi<Block>
65
		+ moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block>
66
		+ moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block>
67
		+ nimbus_primitives::NimbusApi<Block>
68
		+ cumulus_primitives_core::CollectCollationInfo<Block>
69
		+ session_keys_primitives::VrfApi<Block>
70
		+ async_backing_primitives::UnincludedSegmentApi<Block>
71
		+ xcm_runtime_apis::fees::XcmPaymentApi<Block>
72
{
73
}
74

            
75
/// Config that abstracts over all available client implementations.
76
///
77
/// For a concrete type there exists [`Client`].
78
pub trait AbstractClient<Block, Backend>:
79
	BlockchainEvents<Block>
80
	+ Sized
81
	+ Send
82
	+ Sync
83
	+ ProvideRuntimeApi<Block>
84
	+ HeaderBackend<Block>
85
	+ CallApiAt<Block, StateBackend = Backend::State>
86
where
87
	Block: BlockT,
88
	Backend: BackendT<Block>,
89
	Backend::State: sc_client_api::backend::StateBackend<BlakeTwo256>,
90
	Self::Api: RuntimeApiCollection,
91
{
92
}
93

            
94
impl<Block, Backend, Client> AbstractClient<Block, Backend> for Client
95
where
96
	Block: BlockT,
97
	Backend: BackendT<Block>,
98
	Backend::State: sc_client_api::backend::StateBackend<BlakeTwo256>,
99
	Client: BlockchainEvents<Block>
100
		+ ProvideRuntimeApi<Block>
101
		+ HeaderBackend<Block>
102
		+ Sized
103
		+ Send
104
		+ Sync
105
		+ CallApiAt<Block, StateBackend = Backend::State>,
106
	Client::Api: RuntimeApiCollection,
107
{
108
}
109

            
110
/// Execute something with the client instance.
111
///
112
/// As there exist multiple chains inside Moonbeam, like Moonbeam itself, Moonbase,
113
/// Moonriver etc, there can exist different kinds of client types. As these
114
/// client types differ in the generics that are being used, we can not easily
115
/// return them from a function. For returning them from a function there exists
116
/// [`Client`]. However, the problem on how to use this client instance still
117
/// exists. This trait "solves" it in a dirty way. It requires a type to
118
/// implement this trait and than the [`execute_with_client`](ExecuteWithClient:
119
/// :execute_with_client) function can be called with any possible client
120
/// instance.
121
///
122
/// In a perfect world, we could make a closure work in this way.
123
pub trait ExecuteWithClient {
124
	/// The return type when calling this instance.
125
	type Output;
126

            
127
	/// Execute whatever should be executed with the given client instance.
128
	fn execute_with_client<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
129
	where
130
		Backend: sc_client_api::Backend<Block>,
131
		Backend::State: sc_client_api::backend::StateBackend<BlakeTwo256>,
132
		Api: crate::RuntimeApiCollection,
133
		Client: AbstractClient<Block, Backend, Api = Api> + 'static;
134
}
135

            
136
/// A handle to a Moonbeam client instance.
137
///
138
/// The Moonbeam service supports multiple different runtimes (Moonbase, Moonbeam
139
/// itself, etc). As each runtime has a specialized client, we need to hide them
140
/// behind a trait. This is this trait.
141
///
142
/// When wanting to work with the inner client, you need to use `execute_with`.
143
pub trait ClientHandle {
144
	/// Execute the given something with the client.
145
	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output;
146
}
147

            
148
/// A client instance of Moonbeam.
149
#[derive(Clone)]
150
pub enum Client {
151
	#[cfg(feature = "moonbeam-native")]
152
	Moonbeam(Arc<crate::FullClient<moonbeam_runtime::RuntimeApi>>),
153
	#[cfg(feature = "moonriver-native")]
154
	Moonriver(Arc<crate::FullClient<moonriver_runtime::RuntimeApi>>),
155
	#[cfg(feature = "moonbase-native")]
156
	Moonbase(Arc<crate::FullClient<moonbase_runtime::RuntimeApi>>),
157
}
158

            
159
#[cfg(feature = "moonbeam-native")]
160
impl From<Arc<crate::FullClient<moonbeam_runtime::RuntimeApi>>> for Client {
161
	fn from(client: Arc<crate::FullClient<moonbeam_runtime::RuntimeApi>>) -> Self {
162
		Self::Moonbeam(client)
163
	}
164
}
165

            
166
#[cfg(feature = "moonriver-native")]
167
impl From<Arc<crate::FullClient<moonriver_runtime::RuntimeApi>>> for Client {
168
	fn from(client: Arc<crate::FullClient<moonriver_runtime::RuntimeApi>>) -> Self {
169
		Self::Moonriver(client)
170
	}
171
}
172

            
173
#[cfg(feature = "moonbase-native")]
174
impl From<Arc<crate::FullClient<moonbase_runtime::RuntimeApi>>> for Client {
175
	fn from(client: Arc<crate::FullClient<moonbase_runtime::RuntimeApi>>) -> Self {
176
		Self::Moonbase(client)
177
	}
178
}
179

            
180
impl ClientHandle for Client {
181
	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output {
182
		match self {
183
			#[cfg(feature = "moonbeam-native")]
184
			Self::Moonbeam(client) => T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()),
185
			#[cfg(feature = "moonriver-native")]
186
			Self::Moonriver(client) => T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()),
187
			#[cfg(feature = "moonbase-native")]
188
			Self::Moonbase(client) => T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()),
189
		}
190
	}
191
}
192

            
193
macro_rules! match_client {
194
	($self:ident, $method:ident($($param:ident),*)) => {
195
		match $self {
196
			#[cfg(feature = "moonbeam-native")]
197
			Self::Moonbeam(client) => client.$method($($param),*),
198
			#[cfg(feature = "moonriver-native")]
199
			Self::Moonriver(client) => client.$method($($param),*),
200
			#[cfg(feature = "moonbase-native")]
201
			Self::Moonbase(client) => client.$method($($param),*),
202
		}
203
	};
204
}
205

            
206
impl sc_client_api::UsageProvider<Block> for Client {
207
	fn usage_info(&self) -> sc_client_api::ClientInfo<Block> {
208
		match_client!(self, usage_info())
209
	}
210
}
211

            
212
impl sc_client_api::BlockBackend<Block> for Client {
213
	fn block_body(
214
		&self,
215
		hash: <Block as BlockT>::Hash,
216
	) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
217
		match_client!(self, block_body(hash))
218
	}
219

            
220
	fn block_indexed_body(
221
		&self,
222
		hash: <Block as BlockT>::Hash,
223
	) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
224
		match_client!(self, block_indexed_body(hash))
225
	}
226

            
227
	fn block(
228
		&self,
229
		hash: <Block as BlockT>::Hash,
230
	) -> sp_blockchain::Result<Option<SignedBlock<Block>>> {
231
		match_client!(self, block(hash))
232
	}
233

            
234
	fn block_status(&self, hash: <Block as BlockT>::Hash) -> sp_blockchain::Result<BlockStatus> {
235
		match_client!(self, block_status(hash))
236
	}
237

            
238
	fn justifications(
239
		&self,
240
		hash: <Block as BlockT>::Hash,
241
	) -> sp_blockchain::Result<Option<Justifications>> {
242
		match_client!(self, justifications(hash))
243
	}
244

            
245
	fn block_hash(
246
		&self,
247
		number: NumberFor<Block>,
248
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
249
		match_client!(self, block_hash(number))
250
	}
251

            
252
	fn indexed_transaction(
253
		&self,
254
		hash: <Block as BlockT>::Hash,
255
	) -> sp_blockchain::Result<Option<Vec<u8>>> {
256
		match_client!(self, indexed_transaction(hash))
257
	}
258

            
259
	fn has_indexed_transaction(
260
		&self,
261
		hash: <Block as BlockT>::Hash,
262
	) -> sp_blockchain::Result<bool> {
263
		match_client!(self, has_indexed_transaction(hash))
264
	}
265

            
266
	fn requires_full_sync(&self) -> bool {
267
		match_client!(self, requires_full_sync())
268
	}
269
}
270

            
271
impl sc_client_api::StorageProvider<Block, crate::FullBackend> for Client {
272
	fn storage(
273
		&self,
274
		hash: <Block as BlockT>::Hash,
275
		key: &StorageKey,
276
	) -> sp_blockchain::Result<Option<StorageData>> {
277
		match_client!(self, storage(hash, key))
278
	}
279

            
280
	fn storage_hash(
281
		&self,
282
		hash: <Block as BlockT>::Hash,
283
		key: &StorageKey,
284
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
285
		match_client!(self, storage_hash(hash, key))
286
	}
287

            
288
	fn storage_keys(
289
		&self,
290
		hash: <Block as BlockT>::Hash,
291
		prefix: Option<&StorageKey>,
292
		start_key: Option<&StorageKey>,
293
	) -> sp_blockchain::Result<
294
		KeysIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
295
	> {
296
		match_client!(self, storage_keys(hash, prefix, start_key))
297
	}
298

            
299
	fn storage_pairs(
300
		&self,
301
		hash: <Block as BlockT>::Hash,
302
		key_prefix: Option<&StorageKey>,
303
		start_key: Option<&StorageKey>,
304
	) -> sp_blockchain::Result<
305
		PairsIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
306
	> {
307
		match_client!(self, storage_pairs(hash, key_prefix, start_key))
308
	}
309

            
310
	fn child_storage(
311
		&self,
312
		hash: <Block as BlockT>::Hash,
313
		child_info: &ChildInfo,
314
		key: &StorageKey,
315
	) -> sp_blockchain::Result<Option<StorageData>> {
316
		match_client!(self, child_storage(hash, child_info, key))
317
	}
318

            
319
	fn child_storage_keys(
320
		&self,
321
		hash: <Block as BlockT>::Hash,
322
		child_info: ChildInfo,
323
		prefix: Option<&StorageKey>,
324
		start_key: Option<&StorageKey>,
325
	) -> sp_blockchain::Result<
326
		KeysIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
327
	> {
328
		match_client!(
329
			self,
330
			child_storage_keys(hash, child_info, prefix, start_key)
331
		)
332
	}
333

            
334
	fn child_storage_hash(
335
		&self,
336
		hash: <Block as BlockT>::Hash,
337
		child_info: &ChildInfo,
338
		key: &StorageKey,
339
	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
340
		match_client!(self, child_storage_hash(hash, child_info, key))
341
	}
342

            
343
	fn closest_merkle_value(
344
		&self,
345
		hash: <Block as BlockT>::Hash,
346
		key: &StorageKey,
347
	) -> sp_blockchain::Result<Option<MerkleValue<<Block as BlockT>::Hash>>> {
348
		match_client!(self, closest_merkle_value(hash, key))
349
	}
350

            
351
	fn child_closest_merkle_value(
352
		&self,
353
		hash: <Block as BlockT>::Hash,
354
		child_info: &ChildInfo,
355
		key: &StorageKey,
356
	) -> sp_blockchain::Result<Option<MerkleValue<<Block as BlockT>::Hash>>> {
357
		match_client!(self, child_closest_merkle_value(hash, child_info, key))
358
	}
359
}
360

            
361
impl sp_blockchain::HeaderBackend<Block> for Client {
362
	fn header(&self, hash: Hash) -> sp_blockchain::Result<Option<Header>> {
363
		match_client!(self, header(hash))
364
	}
365

            
366
	fn info(&self) -> sp_blockchain::Info<Block> {
367
		match_client!(self, info())
368
	}
369

            
370
	fn status(&self, hash: Hash) -> sp_blockchain::Result<sp_blockchain::BlockStatus> {
371
		match_client!(self, status(hash))
372
	}
373

            
374
	fn number(&self, hash: Hash) -> sp_blockchain::Result<Option<BlockNumber>> {
375
		match_client!(self, number(hash))
376
	}
377

            
378
	fn hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Hash>> {
379
		match_client!(self, hash(number))
380
	}
381
}