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
use ethereum_types::{H160, H256, U256};
18
use fc_rpc::{internal_err, public_key};
19
use jsonrpsee::core::RpcResult;
20
pub use moonbeam_rpc_core_txpool::{
21
	GetT, Summary, Transaction, TransactionMap, TxPoolResult, TxPoolServer,
22
};
23
use sc_transaction_pool::{ChainApi, Pool};
24
use sc_transaction_pool_api::InPoolTransaction;
25
use serde::Serialize;
26
use sha3::{Digest, Keccak256};
27
use sp_api::{ApiExt, ProvideRuntimeApi};
28
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
29
use sp_runtime::traits::Block as BlockT;
30
use std::collections::HashMap;
31
use std::{marker::PhantomData, sync::Arc};
32

            
33
use moonbeam_rpc_primitives_txpool::{
34
	Transaction as TransactionV2, TxPoolResponse, TxPoolRuntimeApi,
35
};
36

            
37
pub struct TxPool<B: BlockT, C, A: ChainApi> {
38
	client: Arc<C>,
39
	graph: Arc<Pool<A>>,
40
	_marker: PhantomData<B>,
41
}
42

            
43
impl<B, C, A> TxPool<B, C, A>
44
where
45
	C: ProvideRuntimeApi<B>,
46
	C: HeaderMetadata<B, Error = BlockChainError> + HeaderBackend<B> + 'static,
47
	C: Send + Sync + 'static,
48
	B: BlockT<Hash = H256> + Send + Sync + 'static,
49
	A: ChainApi<Block = B> + 'static,
50
	C::Api: TxPoolRuntimeApi<B>,
51
{
52
	/// Use the transaction graph interface to get the extrinsics currently in the ready and future
53
	/// queues.
54
30
	fn map_build<T>(&self) -> RpcResult<TxPoolResult<TransactionMap<T>>>
55
30
	where
56
30
		T: GetT + Serialize,
57
30
	{
58
30
		// Collect transactions in the ready validated pool.
59
30
		let txs_ready = self
60
30
			.graph
61
30
			.validated_pool()
62
30
			.ready()
63
48560
			.map(|in_pool_tx| in_pool_tx.data().clone())
64
30
			.collect();
65
30

            
66
30
		// Collect transactions in the future validated pool.
67
30
		let txs_future = self
68
30
			.graph
69
30
			.validated_pool()
70
30
			.futures()
71
30
			.iter()
72
30
			.map(|(_hash, extrinsic)| extrinsic.clone())
73
30
			.collect();
74
30

            
75
30
		// Use the runtime to match the (here) opaque extrinsics against ethereum transactions.
76
30
		let best_block = self.client.info().best_hash;
77
30
		let api = self.client.runtime_api();
78
30
		let api_version =
79
30
			if let Ok(Some(api_version)) = api.api_version::<dyn TxPoolRuntimeApi<B>>(best_block) {
80
30
				api_version
81
			} else {
82
				return Err(internal_err(
83
					"failed to retrieve Runtime Api version".to_string(),
84
				));
85
			};
86
30
		let ethereum_txns: TxPoolResponse = if api_version == 1 {
87
			#[allow(deprecated)]
88
			let res = api.extrinsic_filter_before_version_2(best_block, txs_ready, txs_future)
89
				.map_err(|err| {
90
					internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err))
91
				})?;
92
			TxPoolResponse {
93
				ready: res
94
					.ready
95
					.iter()
96
					.map(|t| TransactionV2::Legacy(t.clone()))
97
					.collect(),
98
				future: res
99
					.future
100
					.iter()
101
					.map(|t| TransactionV2::Legacy(t.clone()))
102
					.collect(),
103
			}
104
		} else {
105
30
			api.extrinsic_filter(best_block, txs_ready, txs_future)
106
30
				.map_err(|err| {
107
					internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err))
108
30
				})?
109
		};
110
		// Build the T response.
111
30
		let mut pending = TransactionMap::<T>::new();
112
48560
		for txn in ethereum_txns.ready.iter() {
113
48560
			let hash = txn.hash();
114
48560
			let nonce = match txn {
115
48560
				TransactionV2::Legacy(t) => t.nonce,
116
				TransactionV2::EIP2930(t) => t.nonce,
117
				TransactionV2::EIP1559(t) => t.nonce,
118
			};
119
48560
			let from_address = match public_key(txn) {
120
48560
				Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())),
121
				Err(_e) => H160::default(),
122
			};
123
48560
			pending
124
48560
				.entry(from_address)
125
48560
				.or_insert_with(HashMap::new)
126
48560
				.insert(nonce, T::get(hash, from_address, txn));
127
		}
128
30
		let mut queued = TransactionMap::<T>::new();
129
30
		for txn in ethereum_txns.future.iter() {
130
4
			let hash = txn.hash();
131
4
			let nonce = match txn {
132
4
				TransactionV2::Legacy(t) => t.nonce,
133
				TransactionV2::EIP2930(t) => t.nonce,
134
				TransactionV2::EIP1559(t) => t.nonce,
135
			};
136
4
			let from_address = match public_key(txn) {
137
4
				Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())),
138
				Err(_e) => H160::default(),
139
			};
140
4
			queued
141
4
				.entry(from_address)
142
4
				.or_insert_with(HashMap::new)
143
4
				.insert(nonce, T::get(hash, from_address, txn));
144
		}
145
30
		Ok(TxPoolResult { pending, queued })
146
30
	}
147
}
148

            
149
impl<B: BlockT, C, A: ChainApi> TxPool<B, C, A> {
150
1788
	pub fn new(client: Arc<C>, graph: Arc<Pool<A>>) -> Self {
151
1788
		Self {
152
1788
			client,
153
1788
			graph,
154
1788
			_marker: PhantomData,
155
1788
		}
156
1788
	}
157
}
158

            
159
impl<B, C, A> TxPoolServer for TxPool<B, C, A>
160
where
161
	C: ProvideRuntimeApi<B>,
162
	C: HeaderMetadata<B, Error = BlockChainError> + HeaderBackend<B>,
163
	C: Send + Sync + 'static,
164
	B: BlockT<Hash = H256> + Send + Sync + 'static,
165
	A: ChainApi<Block = B> + 'static,
166
	C::Api: TxPoolRuntimeApi<B>,
167
{
168
6
	fn content(&self) -> RpcResult<TxPoolResult<TransactionMap<Transaction>>> {
169
6
		self.map_build::<Transaction>()
170
6
	}
171

            
172
24
	fn inspect(&self) -> RpcResult<TxPoolResult<TransactionMap<Summary>>> {
173
24
		self.map_build::<Summary>()
174
24
	}
175

            
176
	fn status(&self) -> RpcResult<TxPoolResult<U256>> {
177
		let status = self.graph.validated_pool().status();
178
		Ok(TxPoolResult {
179
			pending: U256::from(status.ready),
180
			queued: U256::from(status.future),
181
		})
182
	}
183
}
184

            
185
impl<B: BlockT, C, A: ChainApi> Clone for TxPool<B, C, A> {
186
	fn clone(&self) -> Self {
187
		Self::new(self.client.clone(), self.graph.clone())
188
	}
189
}