sc_transaction_pool/
builder.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Utility for building substrate transaction pool trait object.
20
21use crate::{
22	common::api::FullChainApi,
23	fork_aware_txpool::ForkAwareTxPool as ForkAwareFullPool,
24	graph::{base_pool::Transaction, ChainApi, ExtrinsicFor, ExtrinsicHash, IsValidator, Options},
25	single_state_txpool::BasicPool as SingleStateFullPool,
26	TransactionPoolWrapper, LOG_TARGET,
27};
28use prometheus_endpoint::Registry as PrometheusRegistry;
29use sc_transaction_pool_api::{LocalTransactionPool, MaintainedTransactionPool};
30use sp_core::traits::SpawnEssentialNamed;
31use sp_runtime::traits::Block as BlockT;
32use std::{marker::PhantomData, sync::Arc, time::Duration};
33
34/// The type of transaction pool.
35#[derive(Debug, Clone)]
36pub enum TransactionPoolType {
37	/// Single-state transaction pool
38	SingleState,
39	/// Fork-aware transaction pool
40	ForkAware,
41}
42
43/// Transaction pool options.
44#[derive(Debug, Clone)]
45pub struct TransactionPoolOptions {
46	txpool_type: TransactionPoolType,
47	options: Options,
48}
49
50impl Default for TransactionPoolOptions {
51	fn default() -> Self {
52		Self { txpool_type: TransactionPoolType::SingleState, options: Default::default() }
53	}
54}
55
56impl TransactionPoolOptions {
57	/// Creates the options for the transaction pool using given parameters.
58	pub fn new_with_params(
59		pool_limit: usize,
60		pool_bytes: usize,
61		tx_ban_seconds: Option<u64>,
62		txpool_type: TransactionPoolType,
63		is_dev: bool,
64	) -> TransactionPoolOptions {
65		let mut options = Options::default();
66
67		// ready queue
68		options.ready.count = pool_limit;
69		options.ready.total_bytes = pool_bytes;
70
71		// future queue
72		let factor = 10;
73		options.future.count = pool_limit / factor;
74		options.future.total_bytes = pool_bytes / factor;
75
76		options.ban_time = if let Some(ban_seconds) = tx_ban_seconds {
77			Duration::from_secs(ban_seconds)
78		} else if is_dev {
79			Duration::from_secs(0)
80		} else {
81			Duration::from_secs(30 * 60)
82		};
83
84		TransactionPoolOptions { options, txpool_type }
85	}
86
87	/// Creates predefined options for benchmarking
88	pub fn new_for_benchmarks() -> TransactionPoolOptions {
89		TransactionPoolOptions {
90			options: Options {
91				ready: crate::graph::base_pool::Limit {
92					count: 100_000,
93					total_bytes: 100 * 1024 * 1024,
94				},
95				future: crate::graph::base_pool::Limit {
96					count: 100_000,
97					total_bytes: 100 * 1024 * 1024,
98				},
99				reject_future_transactions: false,
100				ban_time: Duration::from_secs(30 * 60),
101			},
102			txpool_type: TransactionPoolType::SingleState,
103		}
104	}
105}
106
107/// `FullClientTransactionPool` is a trait that combines the functionality of
108/// `MaintainedTransactionPool` and `LocalTransactionPool` for a given `Client` and `Block`.
109///
110/// This trait defines the requirements for a full client transaction pool, ensuring
111/// that it can handle transactions submission and maintenance.
112pub trait FullClientTransactionPool<Block, Client>:
113	MaintainedTransactionPool<
114		Block = Block,
115		Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
116		InPoolTransaction = Transaction<
117			ExtrinsicHash<FullChainApi<Client, Block>>,
118			ExtrinsicFor<FullChainApi<Client, Block>>,
119		>,
120		Error = <FullChainApi<Client, Block> as ChainApi>::Error,
121	> + LocalTransactionPool<
122		Block = Block,
123		Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
124		Error = <FullChainApi<Client, Block> as ChainApi>::Error,
125	>
126where
127	Block: BlockT,
128	Client: sp_api::ProvideRuntimeApi<Block>
129		+ sc_client_api::BlockBackend<Block>
130		+ sc_client_api::blockchain::HeaderBackend<Block>
131		+ sp_runtime::traits::BlockIdTo<Block>
132		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
133		+ 'static,
134	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
135{
136}
137
138impl<Block, Client, P> FullClientTransactionPool<Block, Client> for P
139where
140	Block: BlockT,
141	Client: sp_api::ProvideRuntimeApi<Block>
142		+ sc_client_api::BlockBackend<Block>
143		+ sc_client_api::blockchain::HeaderBackend<Block>
144		+ sp_runtime::traits::BlockIdTo<Block>
145		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
146		+ 'static,
147	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
148	P: MaintainedTransactionPool<
149			Block = Block,
150			Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
151			InPoolTransaction = Transaction<
152				ExtrinsicHash<FullChainApi<Client, Block>>,
153				ExtrinsicFor<FullChainApi<Client, Block>>,
154			>,
155			Error = <FullChainApi<Client, Block> as ChainApi>::Error,
156		> + LocalTransactionPool<
157			Block = Block,
158			Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
159			Error = <FullChainApi<Client, Block> as ChainApi>::Error,
160		>,
161{
162}
163
164/// The public type alias for the actual type providing the implementation of
165/// `FullClientTransactionPool` with the given `Client` and `Block` types.
166///
167/// This handle abstracts away the specific type of the transaction pool. Should be used
168/// externally to keep reference to transaction pool.
169pub type TransactionPoolHandle<Block, Client> = TransactionPoolWrapper<Block, Client>;
170
171/// Builder allowing to create specific instance of transaction pool.
172pub struct Builder<'a, Block, Client> {
173	options: TransactionPoolOptions,
174	is_validator: IsValidator,
175	prometheus: Option<&'a PrometheusRegistry>,
176	client: Arc<Client>,
177	spawner: Box<dyn SpawnEssentialNamed>,
178	_phantom: PhantomData<(Client, Block)>,
179}
180
181impl<'a, Client, Block> Builder<'a, Block, Client>
182where
183	Block: BlockT,
184	Client: sp_api::ProvideRuntimeApi<Block>
185		+ sc_client_api::BlockBackend<Block>
186		+ sc_client_api::blockchain::HeaderBackend<Block>
187		+ sp_runtime::traits::BlockIdTo<Block>
188		+ sc_client_api::ExecutorProvider<Block>
189		+ sc_client_api::UsageProvider<Block>
190		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
191		+ Send
192		+ Sync
193		+ 'static,
194	<Block as BlockT>::Hash: std::marker::Unpin,
195	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
196{
197	/// Creates new instance of `Builder`
198	pub fn new(
199		spawner: impl SpawnEssentialNamed + 'static,
200		client: Arc<Client>,
201		is_validator: IsValidator,
202	) -> Builder<'a, Block, Client> {
203		Builder {
204			options: Default::default(),
205			_phantom: Default::default(),
206			spawner: Box::new(spawner),
207			client,
208			is_validator,
209			prometheus: None,
210		}
211	}
212
213	/// Sets the options used for creating a transaction pool instance.
214	pub fn with_options(mut self, options: TransactionPoolOptions) -> Self {
215		self.options = options;
216		self
217	}
218
219	/// Sets the prometheus endpoint used in a transaction pool instance.
220	pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self {
221		self.prometheus = prometheus;
222		self
223	}
224
225	/// Creates an instance of transaction pool.
226	pub fn build(self) -> TransactionPoolHandle<Block, Client> {
227		log::info!(target:LOG_TARGET, " creating {:?} txpool {:?}/{:?}.", self.options.txpool_type, self.options.options.ready, self.options.options.future);
228		TransactionPoolWrapper::<Block, Client>(match self.options.txpool_type {
229			TransactionPoolType::SingleState => Box::new(SingleStateFullPool::new_full(
230				self.options.options,
231				self.is_validator,
232				self.prometheus,
233				self.spawner,
234				self.client,
235			)),
236			TransactionPoolType::ForkAware => Box::new(ForkAwareFullPool::new_full(
237				self.options.options,
238				self.is_validator,
239				self.prometheus,
240				self.spawner,
241				self.client,
242			)),
243		})
244	}
245}