1use crate::{
22 fork_aware_txpool::ForkAwareTxPool as ForkAwareFullPool,
23 graph::{base_pool::Transaction, IsValidator, Options},
24 single_state_txpool::BasicPool as SingleStateFullPool,
25 LOG_TARGET,
26};
27use prometheus_endpoint::Registry as PrometheusRegistry;
28use sc_transaction_pool_api::{LocalTransactionPool, MaintainedTransactionPool};
29use sp_core::traits::SpawnEssentialNamed;
30use sp_runtime::traits::Block as BlockT;
31use std::{marker::PhantomData, sync::Arc, time::Duration};
32
33#[derive(Debug, Clone)]
35pub enum TransactionPoolType {
36 SingleState,
38 ForkAware,
40}
41
42#[derive(Debug, Clone)]
44pub struct TransactionPoolOptions {
45 txpool_type: TransactionPoolType,
46 options: Options,
47 best_blocks_only: bool,
51}
52
53impl Default for TransactionPoolOptions {
54 fn default() -> Self {
55 Self {
56 txpool_type: TransactionPoolType::SingleState,
57 options: Default::default(),
58 best_blocks_only: false,
59 }
60 }
61}
62
63impl TransactionPoolOptions {
64 pub fn new_with_params(
66 pool_limit: usize,
67 pool_bytes: usize,
68 tx_ban_seconds: Option<u64>,
69 txpool_type: TransactionPoolType,
70 is_dev: bool,
71 best_blocks_only: bool,
72 ) -> TransactionPoolOptions {
73 let mut options = Options::default();
74
75 options.ready.count = pool_limit;
77 options.ready.total_bytes = pool_bytes;
78
79 let factor = 10;
81 options.future.count = pool_limit / factor;
82 options.future.total_bytes = pool_bytes / factor;
83
84 options.ban_time = if let Some(ban_seconds) = tx_ban_seconds {
85 Duration::from_secs(ban_seconds)
86 } else if is_dev {
87 Duration::from_secs(0)
88 } else {
89 Duration::from_secs(30 * 60)
90 };
91
92 TransactionPoolOptions { options, txpool_type, best_blocks_only }
93 }
94
95 pub fn new_for_benchmarks() -> TransactionPoolOptions {
97 TransactionPoolOptions {
98 options: Options {
99 ready: crate::graph::base_pool::Limit {
100 count: 100_000,
101 total_bytes: 100 * 1024 * 1024,
102 },
103 future: crate::graph::base_pool::Limit {
104 count: 100_000,
105 total_bytes: 100 * 1024 * 1024,
106 },
107 reject_future_transactions: false,
108 ban_time: Duration::from_secs(30 * 60),
109 },
110 txpool_type: TransactionPoolType::SingleState,
111 best_blocks_only: false,
112 }
113 }
114
115 pub fn use_all_block_notifications(&self) -> bool {
117 matches!(self.txpool_type, TransactionPoolType::ForkAware) && !self.best_blocks_only
118 }
119}
120
121pub trait ClientForTransactionPool<Block: BlockT>:
128 sp_api::ProvideRuntimeApi<
129 Block,
130 Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
131 > + sc_client_api::BlockBackend<Block>
132 + sc_client_api::blockchain::HeaderBackend<Block>
133 + sp_runtime::traits::BlockIdTo<Block>
134 + sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
135 + 'static
136{
137}
138
139impl<Block: BlockT, T> ClientForTransactionPool<Block> for T where
140 T: sp_api::ProvideRuntimeApi<
141 Block,
142 Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
143 > + sc_client_api::BlockBackend<Block>
144 + sc_client_api::blockchain::HeaderBackend<Block>
145 + sp_runtime::traits::BlockIdTo<Block>
146 + sp_blockchain::HeaderMetadata<Block, Error = sp_blockchain::Error>
147 + 'static
148{
149}
150
151pub trait FullClientTransactionPool<Block>: MaintainedTransactionPool<
160 Block = Block,
161 Hash = <Block as BlockT>::Hash,
162 InPoolTransaction = Transaction<<Block as BlockT>::Hash, Arc<<Block as BlockT>::Extrinsic>>,
163 Error = crate::error::Error,
164 > + LocalTransactionPool<Block = Block, Hash = <Block as BlockT>::Hash, Error = crate::error::Error>
165where
166 Block: BlockT,
167{
168}
169
170impl<Block, P> FullClientTransactionPool<Block> for P
171where
172 Block: BlockT,
173 P: MaintainedTransactionPool<
174 Block = Block,
175 Hash = <Block as BlockT>::Hash,
176 InPoolTransaction = Transaction<
177 <Block as BlockT>::Hash,
178 Arc<<Block as BlockT>::Extrinsic>,
179 >,
180 Error = crate::error::Error,
181 > + LocalTransactionPool<
182 Block = Block,
183 Hash = <Block as BlockT>::Hash,
184 Error = crate::error::Error,
185 >,
186{
187}
188
189pub type TransactionPoolHandle<Block> = dyn FullClientTransactionPool<Block>;
195
196pub struct Builder<'a, Block, Client> {
198 options: TransactionPoolOptions,
199 is_validator: IsValidator,
200 prometheus: Option<&'a PrometheusRegistry>,
201 client: Arc<Client>,
202 spawner: Box<dyn SpawnEssentialNamed>,
203 _phantom: PhantomData<(Client, Block)>,
204}
205
206impl<'a, Client, Block> Builder<'a, Block, Client>
207where
208 Block: BlockT,
209 Client: ClientForTransactionPool<Block>
210 + sc_client_api::ExecutorProvider<Block>
211 + sc_client_api::UsageProvider<Block>,
212 <Block as BlockT>::Hash: std::marker::Unpin,
213{
214 pub fn new(
216 spawner: impl SpawnEssentialNamed + 'static,
217 client: Arc<Client>,
218 is_validator: IsValidator,
219 ) -> Builder<'a, Block, Client> {
220 Builder {
221 options: Default::default(),
222 _phantom: Default::default(),
223 spawner: Box::new(spawner),
224 client,
225 is_validator,
226 prometheus: None,
227 }
228 }
229
230 pub fn with_options(mut self, options: TransactionPoolOptions) -> Self {
232 self.options = options;
233 self
234 }
235
236 pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self {
238 self.prometheus = prometheus;
239 self
240 }
241
242 pub fn build(self) -> Arc<TransactionPoolHandle<Block>> {
244 tracing::info!(
245 target: LOG_TARGET,
246 txpool_type = ?self.options.txpool_type,
247 ready = ?self.options.options.ready,
248 future = ?self.options.options.future,
249 "Creating transaction pool"
250 );
251 match self.options.txpool_type {
252 TransactionPoolType::SingleState => Arc::new(SingleStateFullPool::new_full(
253 self.options.options,
254 self.is_validator,
255 self.prometheus,
256 self.spawner,
257 self.client,
258 )),
259 TransactionPoolType::ForkAware => Arc::new(ForkAwareFullPool::new_full(
260 self.options.options,
261 self.is_validator,
262 self.prometheus,
263 self.spawner,
264 self.client,
265 )),
266 }
267 }
268}