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}
49
50impl Default for TransactionPoolOptions {
51 fn default() -> Self {
52 Self { txpool_type: TransactionPoolType::SingleState, options: Default::default() }
53 }
54}
55
56impl TransactionPoolOptions {
57 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 options.ready.count = pool_limit;
69 options.ready.total_bytes = pool_bytes;
70
71 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 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
107pub 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
164pub type TransactionPoolHandle<Block, Client> = TransactionPoolWrapper<Block, Client>;
170
171pub 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 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 pub fn with_options(mut self, options: TransactionPoolOptions) -> Self {
215 self.options = options;
216 self
217 }
218
219 pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self {
221 self.prometheus = prometheus;
222 self
223 }
224
225 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}