referrerpolicy=no-referrer-when-downgrade

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	/// If `true`, the pool is only maintained on best blocks (legacy behavior).
49	///
50	/// Only relevant for the fork-aware pool.
51	best_blocks_only: bool,
52}
53
54impl Default for TransactionPoolOptions {
55	fn default() -> Self {
56		Self {
57			txpool_type: TransactionPoolType::SingleState,
58			options: Default::default(),
59			best_blocks_only: false,
60		}
61	}
62}
63
64impl TransactionPoolOptions {
65	/// Creates the options for the transaction pool using given parameters.
66	pub fn new_with_params(
67		pool_limit: usize,
68		pool_bytes: usize,
69		tx_ban_seconds: Option<u64>,
70		txpool_type: TransactionPoolType,
71		is_dev: bool,
72		best_blocks_only: bool,
73	) -> TransactionPoolOptions {
74		let mut options = Options::default();
75
76		// ready queue
77		options.ready.count = pool_limit;
78		options.ready.total_bytes = pool_bytes;
79
80		// future queue
81		let factor = 10;
82		options.future.count = pool_limit / factor;
83		options.future.total_bytes = pool_bytes / factor;
84
85		options.ban_time = if let Some(ban_seconds) = tx_ban_seconds {
86			Duration::from_secs(ban_seconds)
87		} else if is_dev {
88			Duration::from_secs(0)
89		} else {
90			Duration::from_secs(30 * 60)
91		};
92
93		TransactionPoolOptions { options, txpool_type, best_blocks_only }
94	}
95
96	/// Creates predefined options for benchmarking
97	pub fn new_for_benchmarks() -> TransactionPoolOptions {
98		TransactionPoolOptions {
99			options: Options {
100				ready: crate::graph::base_pool::Limit {
101					count: 100_000,
102					total_bytes: 100 * 1024 * 1024,
103				},
104				future: crate::graph::base_pool::Limit {
105					count: 100_000,
106					total_bytes: 100 * 1024 * 1024,
107				},
108				reject_future_transactions: false,
109				ban_time: Duration::from_secs(30 * 60),
110			},
111			txpool_type: TransactionPoolType::SingleState,
112			best_blocks_only: false,
113		}
114	}
115
116	/// Returns whether the transaction pool should be notified about *every* imported block.
117	pub fn use_all_block_notifications(&self) -> bool {
118		matches!(self.txpool_type, TransactionPoolType::ForkAware) && !self.best_blocks_only
119	}
120}
121
122/// `FullClientTransactionPool` is a trait that combines the functionality of
123/// `MaintainedTransactionPool` and `LocalTransactionPool` for a given `Client` and `Block`.
124///
125/// This trait defines the requirements for a full client transaction pool, ensuring
126/// that it can handle transactions submission and maintenance.
127pub trait FullClientTransactionPool<Block, Client>:
128	MaintainedTransactionPool<
129		Block = Block,
130		Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
131		InPoolTransaction = Transaction<
132			ExtrinsicHash<FullChainApi<Client, Block>>,
133			ExtrinsicFor<FullChainApi<Client, Block>>,
134		>,
135		Error = <FullChainApi<Client, Block> as ChainApi>::Error,
136	> + LocalTransactionPool<
137		Block = Block,
138		Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
139		Error = <FullChainApi<Client, Block> as ChainApi>::Error,
140	>
141where
142	Block: BlockT,
143	Client: sp_api::ProvideRuntimeApi<Block>
144		+ sc_client_api::BlockBackend<Block>
145		+ sc_client_api::blockchain::HeaderBackend<Block>
146		+ sp_runtime::traits::BlockIdTo<Block>
147		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
148		+ 'static,
149	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
150{
151}
152
153impl<Block, Client, P> FullClientTransactionPool<Block, Client> for P
154where
155	Block: BlockT,
156	Client: sp_api::ProvideRuntimeApi<Block>
157		+ sc_client_api::BlockBackend<Block>
158		+ sc_client_api::blockchain::HeaderBackend<Block>
159		+ sp_runtime::traits::BlockIdTo<Block>
160		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
161		+ 'static,
162	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
163	P: MaintainedTransactionPool<
164			Block = Block,
165			Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
166			InPoolTransaction = Transaction<
167				ExtrinsicHash<FullChainApi<Client, Block>>,
168				ExtrinsicFor<FullChainApi<Client, Block>>,
169			>,
170			Error = <FullChainApi<Client, Block> as ChainApi>::Error,
171		> + LocalTransactionPool<
172			Block = Block,
173			Hash = ExtrinsicHash<FullChainApi<Client, Block>>,
174			Error = <FullChainApi<Client, Block> as ChainApi>::Error,
175		>,
176{
177}
178
179/// The public type alias for the actual type providing the implementation of
180/// `FullClientTransactionPool` with the given `Client` and `Block` types.
181///
182/// This handle abstracts away the specific type of the transaction pool. Should be used
183/// externally to keep reference to transaction pool.
184pub type TransactionPoolHandle<Block, Client> = TransactionPoolWrapper<Block, Client>;
185
186/// Builder allowing to create specific instance of transaction pool.
187pub struct Builder<'a, Block, Client> {
188	options: TransactionPoolOptions,
189	is_validator: IsValidator,
190	prometheus: Option<&'a PrometheusRegistry>,
191	client: Arc<Client>,
192	spawner: Box<dyn SpawnEssentialNamed>,
193	_phantom: PhantomData<(Client, Block)>,
194}
195
196impl<'a, Client, Block> Builder<'a, Block, Client>
197where
198	Block: BlockT,
199	Client: sp_api::ProvideRuntimeApi<Block>
200		+ sc_client_api::BlockBackend<Block>
201		+ sc_client_api::blockchain::HeaderBackend<Block>
202		+ sp_runtime::traits::BlockIdTo<Block>
203		+ sc_client_api::ExecutorProvider<Block>
204		+ sc_client_api::UsageProvider<Block>
205		+ sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
206		+ Send
207		+ Sync
208		+ 'static,
209	<Block as BlockT>::Hash: std::marker::Unpin,
210	Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
211{
212	/// Creates new instance of `Builder`
213	pub fn new(
214		spawner: impl SpawnEssentialNamed + 'static,
215		client: Arc<Client>,
216		is_validator: IsValidator,
217	) -> Builder<'a, Block, Client> {
218		Builder {
219			options: Default::default(),
220			_phantom: Default::default(),
221			spawner: Box::new(spawner),
222			client,
223			is_validator,
224			prometheus: None,
225		}
226	}
227
228	/// Sets the options used for creating a transaction pool instance.
229	pub fn with_options(mut self, options: TransactionPoolOptions) -> Self {
230		self.options = options;
231		self
232	}
233
234	/// Sets the prometheus endpoint used in a transaction pool instance.
235	pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self {
236		self.prometheus = prometheus;
237		self
238	}
239
240	/// Creates an instance of transaction pool.
241	pub fn build(self) -> TransactionPoolHandle<Block, Client> {
242		tracing::info!(
243			target: LOG_TARGET,
244			txpool_type = ?self.options.txpool_type,
245			ready = ?self.options.options.ready,
246			future = ?self.options.options.future,
247			"Creating transaction pool"
248		);
249		TransactionPoolWrapper::<Block, Client>(match self.options.txpool_type {
250			TransactionPoolType::SingleState => Box::new(SingleStateFullPool::new_full(
251				self.options.options,
252				self.is_validator,
253				self.prometheus,
254				self.spawner,
255				self.client,
256			)),
257			TransactionPoolType::ForkAware => Box::new(ForkAwareFullPool::new_full(
258				self.options.options,
259				self.is_validator,
260				self.prometheus,
261				self.spawner,
262				self.client,
263			)),
264		})
265	}
266}