1use 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#[derive(Debug, Clone)]
36pub enum TransactionPoolType {
37 SingleState,
39 ForkAware,
41}
42
43#[derive(Debug, Clone)]
45pub struct TransactionPoolOptions {
46 txpool_type: TransactionPoolType,
47 options: Options,
48 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 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 options.ready.count = pool_limit;
78 options.ready.total_bytes = pool_bytes;
79
80 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 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 pub fn use_all_block_notifications(&self) -> bool {
118 matches!(self.txpool_type, TransactionPoolType::ForkAware) && !self.best_blocks_only
119 }
120}
121
122pub 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
179pub type TransactionPoolHandle<Block, Client> = TransactionPoolWrapper<Block, Client>;
185
186pub 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 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 pub fn with_options(mut self, options: TransactionPoolOptions) -> Self {
230 self.options = options;
231 self
232 }
233
234 pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self {
236 self.prometheus = prometheus;
237 self
238 }
239
240 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}