referrerpolicy=no-referrer-when-downgrade

sc_transaction_pool/graph/
pool.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
19use crate::{common::tracing_log_xt::log_xt_trace, LOG_TARGET};
20use async_trait::async_trait;
21use futures::channel::mpsc::Receiver;
22use indexmap::IndexMap;
23use sc_transaction_pool_api::error;
24use sp_blockchain::{HashAndNumber, TreeRoute};
25use sp_runtime::{
26	generic::BlockId,
27	traits::{self, Block as BlockT, SaturatedConversion},
28	transaction_validity::{
29		TransactionSource, TransactionTag as Tag, TransactionValidity, TransactionValidityError,
30	},
31};
32use std::{
33	collections::HashMap,
34	sync::Arc,
35	time::{Duration, Instant},
36};
37use tracing::{debug, instrument, trace, Level};
38
39use super::{
40	base_pool as base,
41	validated_pool::{IsValidator, ValidatedPool, ValidatedTransaction},
42	EventHandler, ValidatedPoolSubmitOutcome,
43};
44
45/// Modification notification event stream type;
46pub type EventStream<H> = Receiver<H>;
47
48/// Block hash type for a pool.
49pub type BlockHash<A> = <<A as ChainApi>::Block as traits::Block>::Hash;
50/// Extrinsic hash type for a pool.
51pub type ExtrinsicHash<A> = <<A as ChainApi>::Block as traits::Block>::Hash;
52/// Extrinsic type for a pool (reference counted).
53pub type ExtrinsicFor<A> = Arc<<<A as ChainApi>::Block as traits::Block>::Extrinsic>;
54/// Extrinsic type for a pool (raw data).
55pub type RawExtrinsicFor<A> = <<A as ChainApi>::Block as traits::Block>::Extrinsic;
56/// Block number type for the ChainApi
57pub type NumberFor<A> = traits::NumberFor<<A as ChainApi>::Block>;
58/// A type of transaction stored in the pool
59pub type TransactionFor<A> = Arc<base::Transaction<ExtrinsicHash<A>, ExtrinsicFor<A>>>;
60/// A type of validated transaction stored in the pool.
61pub type ValidatedTransactionFor<A> =
62	ValidatedTransaction<ExtrinsicHash<A>, ExtrinsicFor<A>, <A as ChainApi>::Error>;
63
64/// The priority of request to validate the transaction.
65#[derive(PartialEq, Copy, Clone)]
66pub enum ValidateTransactionPriority {
67	/// Validate the newly submitted transactions
68	///
69	/// Validation will be done with lower priority.
70	Submitted,
71	/// Validate the transaction during maintainance process,
72	///
73	/// Validation will be performed with higher priority.
74	Maintained,
75}
76
77/// Concrete extrinsic validation and query logic.
78#[async_trait]
79pub trait ChainApi: Send + Sync {
80	/// Block type.
81	type Block: BlockT;
82	/// Error type.
83	type Error: From<error::Error> + error::IntoPoolError + error::IntoMetricsLabel;
84
85	/// Asynchronously verify extrinsic at given block.
86	async fn validate_transaction(
87		&self,
88		at: <Self::Block as BlockT>::Hash,
89		source: TransactionSource,
90		uxt: ExtrinsicFor<Self>,
91		validation_priority: ValidateTransactionPriority,
92	) -> Result<TransactionValidity, Self::Error>;
93
94	/// Synchronously verify given extrinsic at given block.
95	///
96	/// Validates a transaction by calling into the runtime. Same as `validate_transaction` but
97	/// blocks the current thread when performing validation.
98	fn validate_transaction_blocking(
99		&self,
100		at: <Self::Block as BlockT>::Hash,
101		source: TransactionSource,
102		uxt: ExtrinsicFor<Self>,
103	) -> Result<TransactionValidity, Self::Error>;
104
105	/// Returns a block number given the block id.
106	fn block_id_to_number(
107		&self,
108		at: &BlockId<Self::Block>,
109	) -> Result<Option<NumberFor<Self>>, Self::Error>;
110
111	/// Returns a block hash given the block id.
112	fn block_id_to_hash(
113		&self,
114		at: &BlockId<Self::Block>,
115	) -> Result<Option<<Self::Block as BlockT>::Hash>, Self::Error>;
116
117	/// Returns hash and encoding length of the extrinsic.
118	fn hash_and_length(&self, uxt: &RawExtrinsicFor<Self>) -> (ExtrinsicHash<Self>, usize);
119
120	/// Returns a block body given the block.
121	async fn block_body(
122		&self,
123		at: <Self::Block as BlockT>::Hash,
124	) -> Result<Option<Vec<<Self::Block as traits::Block>::Extrinsic>>, Self::Error>;
125
126	/// Returns a block header given the block id.
127	fn block_header(
128		&self,
129		at: <Self::Block as BlockT>::Hash,
130	) -> Result<Option<<Self::Block as BlockT>::Header>, Self::Error>;
131
132	/// Compute a tree-route between two blocks. See [`TreeRoute`] for more details.
133	fn tree_route(
134		&self,
135		from: <Self::Block as BlockT>::Hash,
136		to: <Self::Block as BlockT>::Hash,
137	) -> Result<TreeRoute<Self::Block>, Self::Error>;
138
139	/// Resolves block number by id.
140	fn resolve_block_number(
141		&self,
142		at: <Self::Block as BlockT>::Hash,
143	) -> Result<NumberFor<Self>, Self::Error> {
144		self.block_id_to_number(&BlockId::Hash(at)).and_then(|number| {
145			number.ok_or_else(|| error::Error::InvalidBlockId(format!("{:?}", at)).into())
146		})
147	}
148}
149
150/// Pool configuration options.
151#[derive(Debug, Clone)]
152pub struct Options {
153	/// Ready queue limits.
154	pub ready: base::Limit,
155	/// Future queue limits.
156	pub future: base::Limit,
157	/// Reject future transactions.
158	pub reject_future_transactions: bool,
159	/// How long the extrinsic is banned for.
160	pub ban_time: Duration,
161}
162
163impl Default for Options {
164	fn default() -> Self {
165		Self {
166			ready: base::Limit { count: 8192, total_bytes: 20 * 1024 * 1024 },
167			future: base::Limit { count: 512, total_bytes: 1 * 1024 * 1024 },
168			reject_future_transactions: false,
169			ban_time: Duration::from_secs(60 * 30),
170		}
171	}
172}
173
174impl Options {
175	/// Total (ready+future) maximal number of transactions in the pool.
176	pub fn total_count(&self) -> usize {
177		self.ready.count + self.future.count
178	}
179}
180
181/// Should we check that the transaction is banned
182/// in the pool, before we verify it?
183#[derive(Copy, Clone)]
184pub(crate) enum CheckBannedBeforeVerify {
185	Yes,
186	No,
187}
188
189/// Extrinsics pool that performs validation.
190pub struct Pool<B: ChainApi, L: EventHandler<B>> {
191	validated_pool: Arc<ValidatedPool<B, L>>,
192}
193
194impl<B: ChainApi, L: EventHandler<B>> Pool<B, L> {
195	/// Create a new transaction pool with statically sized rotator.
196	pub fn new_with_staticly_sized_rotator(
197		options: Options,
198		is_validator: IsValidator,
199		api: Arc<B>,
200	) -> Self {
201		Self {
202			validated_pool: Arc::new(ValidatedPool::new_with_staticly_sized_rotator(
203				options,
204				is_validator,
205				api,
206			)),
207		}
208	}
209
210	/// Create a new transaction pool.
211	pub fn new(options: Options, is_validator: IsValidator, api: Arc<B>) -> Self {
212		Self { validated_pool: Arc::new(ValidatedPool::new(options, is_validator, api)) }
213	}
214
215	/// Create a new transaction pool.
216	pub fn new_with_event_handler(
217		options: Options,
218		is_validator: IsValidator,
219		api: Arc<B>,
220		event_handler: L,
221	) -> Self {
222		Self {
223			validated_pool: Arc::new(ValidatedPool::new_with_event_handler(
224				options,
225				is_validator,
226				api,
227				event_handler,
228			)),
229		}
230	}
231
232	/// Imports a bunch of unverified extrinsics to the pool
233	#[instrument(level = Level::TRACE, skip_all, target="txpool", name = "pool::submit_at")]
234	pub async fn submit_at(
235		&self,
236		at: &HashAndNumber<B::Block>,
237		xts: impl IntoIterator<Item = (base::TimedTransactionSource, ExtrinsicFor<B>)>,
238		validation_priority: ValidateTransactionPriority,
239	) -> Vec<Result<ValidatedPoolSubmitOutcome<B>, B::Error>> {
240		let validated_transactions =
241			self.verify(at, xts, CheckBannedBeforeVerify::Yes, validation_priority).await;
242		self.validated_pool.submit(validated_transactions.into_values())
243	}
244
245	/// Resubmit the given extrinsics to the pool.
246	///
247	/// This does not check if a transaction is banned, before we verify it again.
248	pub async fn resubmit_at(
249		&self,
250		at: &HashAndNumber<B::Block>,
251		xts: impl IntoIterator<Item = (base::TimedTransactionSource, ExtrinsicFor<B>)>,
252		validation_priority: ValidateTransactionPriority,
253	) -> Vec<Result<ValidatedPoolSubmitOutcome<B>, B::Error>> {
254		let validated_transactions =
255			self.verify(at, xts, CheckBannedBeforeVerify::No, validation_priority).await;
256		self.validated_pool.submit(validated_transactions.into_values())
257	}
258
259	/// Imports one unverified extrinsic to the pool
260	pub async fn submit_one(
261		&self,
262		at: &HashAndNumber<B::Block>,
263		source: base::TimedTransactionSource,
264		xt: ExtrinsicFor<B>,
265	) -> Result<ValidatedPoolSubmitOutcome<B>, B::Error> {
266		let res = self
267			.submit_at(at, std::iter::once((source, xt)), ValidateTransactionPriority::Submitted)
268			.await
269			.pop();
270		res.expect("One extrinsic passed; one result returned; qed")
271	}
272
273	/// Import a single extrinsic and starts to watch its progress in the pool.
274	pub async fn submit_and_watch(
275		&self,
276		at: &HashAndNumber<B::Block>,
277		source: base::TimedTransactionSource,
278		xt: ExtrinsicFor<B>,
279	) -> Result<ValidatedPoolSubmitOutcome<B>, B::Error> {
280		let (_, tx) = self
281			.verify_one(
282				at.hash,
283				at.number,
284				source,
285				xt,
286				CheckBannedBeforeVerify::Yes,
287				ValidateTransactionPriority::Submitted,
288			)
289			.await;
290		self.validated_pool.submit_and_watch(tx)
291	}
292
293	/// Resubmit some transaction that were validated elsewhere.
294	pub fn resubmit(
295		&self,
296		revalidated_transactions: IndexMap<ExtrinsicHash<B>, ValidatedTransactionFor<B>>,
297	) {
298		let now = Instant::now();
299		self.validated_pool.resubmit(revalidated_transactions);
300		trace!(
301			target: LOG_TARGET,
302			duration = ?now.elapsed(),
303			status = ?self.validated_pool.status(),
304			"Resubmitted transaction."
305		);
306	}
307
308	/// Prunes known ready transactions.
309	///
310	/// Used to clear the pool from transactions that were part of recently imported block.
311	/// The main difference from the `prune` is that we do not revalidate any transactions
312	/// and ignore unknown passed hashes.
313	pub fn prune_known(&self, at: &HashAndNumber<B::Block>, hashes: &[ExtrinsicHash<B>]) {
314		// Get details of all extrinsics that are already in the pool
315		let in_pool_tags =
316			self.validated_pool.extrinsics_tags(hashes).into_iter().flatten().flatten();
317
318		// Prune all transactions that provide given tags
319		let prune_status = self.validated_pool.prune_tags(in_pool_tags);
320		let pruned_transactions =
321			hashes.iter().cloned().chain(prune_status.pruned.iter().map(|tx| tx.hash));
322		self.validated_pool.fire_pruned(at, pruned_transactions);
323	}
324
325	/// Prunes ready transactions.
326	///
327	/// Used to clear the pool from transactions that were part of recently imported block.
328	/// To perform pruning we need the tags that each extrinsic provides and to avoid calling
329	/// into runtime too often we first look up all extrinsics that are in the pool and get
330	/// their provided tags from there. Otherwise we query the runtime at the `parent` block.
331	pub async fn prune(
332		&self,
333		at: &HashAndNumber<B::Block>,
334		parent: <B::Block as BlockT>::Hash,
335		extrinsics: &[RawExtrinsicFor<B>],
336		known_provides_tags: Option<Arc<HashMap<ExtrinsicHash<B>, Vec<Tag>>>>,
337	) {
338		debug!(
339			target: LOG_TARGET,
340			?at,
341			extrinsics_count = extrinsics.len(),
342			"Starting pruning of block."
343		);
344		// Get details of all extrinsics that are already in the pool
345		let in_pool_hashes =
346			extrinsics.iter().map(|extrinsic| self.hash_of(extrinsic)).collect::<Vec<_>>();
347		let in_pool_tags = self.validated_pool.extrinsics_tags(&in_pool_hashes);
348		// Fill unknown tags based on the known tags given in `known_provides_tags`.
349		let mut unknown_txs_count = 0usize;
350		let mut reused_txs_count = 0usize;
351		let tags = in_pool_hashes.iter().zip(in_pool_tags).map(|(tx_hash, tags)| {
352			tags.or_else(|| {
353				unknown_txs_count += 1;
354				known_provides_tags.as_ref().and_then(|inner| {
355					inner.get(&tx_hash).map(|found_tags| {
356						reused_txs_count += 1;
357						found_tags.clone()
358					})
359				})
360			})
361		});
362
363		// Zip the ones from the pool with the full list (we get pairs `(Extrinsic,
364		// Option<Vec<Tag>>)`)
365		let all = extrinsics.iter().zip(tags);
366		let mut validated_counter: usize = 0;
367		let mut future_tags = Vec::new();
368		let now = Instant::now();
369		for (extrinsic, in_pool_tags) in all {
370			match in_pool_tags {
371				// reuse the tags for extrinsics that were found in the pool or given in
372				// `known_provides_tags` cache.
373				Some(tags) => future_tags.extend(tags),
374				// if it's not found in the pool query the runtime at parent block
375				// to get validity info and tags that the extrinsic provides.
376				None => {
377					// Avoid validating block txs if the pool is empty
378					if !self.validated_pool.status().is_empty() {
379						validated_counter = validated_counter + 1;
380						let validity = self
381							.validated_pool
382							.api()
383							.validate_transaction(
384								parent,
385								TransactionSource::InBlock,
386								Arc::from(extrinsic.clone()),
387								ValidateTransactionPriority::Maintained,
388							)
389							.await;
390
391						trace!(
392							target: LOG_TARGET,
393							tx_hash = ?self.validated_pool.api().hash_and_length(&extrinsic.clone()).0,
394							?validity,
395							"prune::revalidated"
396						);
397						if let Ok(Ok(validity)) = validity {
398							future_tags.extend(validity.provides);
399						}
400					} else {
401						trace!(
402							target: LOG_TARGET,
403							?at,
404							"txpool is empty, skipping validation for block",
405						);
406					}
407				},
408			}
409		}
410
411		let known_provides_tags_len = known_provides_tags.map(|inner| inner.len()).unwrap_or(0);
412		debug!(
413			target: LOG_TARGET,
414			validated_counter,
415			known_provides_tags_len,
416			unknown_txs_count,
417			reused_txs_count,
418			duration = ?now.elapsed(),
419			"prune"
420		);
421		self.prune_tags(at, future_tags, in_pool_hashes).await
422	}
423
424	/// Prunes ready transactions that provide given list of tags.
425	///
426	/// Given tags are assumed to be always provided now, so all transactions
427	/// in the Future Queue that require that particular tag (and have other
428	/// requirements satisfied) are promoted to Ready Queue.
429	///
430	/// Moreover for each provided tag we remove transactions in the pool that:
431	/// 1. Provide that tag directly
432	/// 2. Are a dependency of pruned transaction.
433	///
434	/// Returns transactions that have been removed from the pool and must be reverified
435	/// before reinserting to the pool.
436	///
437	/// By removing predecessor transactions as well we might actually end up
438	/// pruning too much, so all removed transactions are reverified against
439	/// the runtime (`validate_transaction`) to make sure they are invalid.
440	///
441	/// However we avoid revalidating transactions that are contained within
442	/// the second parameter of `known_imported_hashes`. These transactions
443	/// (if pruned) are not revalidated and become temporarily banned to
444	/// prevent importing them in the (near) future.
445	pub async fn prune_tags(
446		&self,
447		at: &HashAndNumber<B::Block>,
448		tags: impl IntoIterator<Item = Tag>,
449		known_imported_hashes: impl IntoIterator<Item = ExtrinsicHash<B>> + Clone,
450	) {
451		let now = Instant::now();
452		trace!(target: LOG_TARGET, ?at, "Pruning tags.");
453		// Prune all transactions that provide given tags
454		let prune_status = self.validated_pool.prune_tags(tags);
455
456		// Make sure that we don't revalidate extrinsics that were part of the recently
457		// imported block. This is especially important for UTXO-like chains cause the
458		// inputs are pruned so such transaction would go to future again.
459		self.validated_pool.ban(
460			&Instant::now(),
461			known_imported_hashes.clone().into_iter(),
462			crate::graph::rotator::BanReason::Validation,
463		);
464
465		// Try to re-validate pruned transactions since some of them might be still valid.
466		// note that `known_imported_hashes` will be rejected here due to temporary ban.
467		let pruned_transactions =
468			prune_status.pruned.into_iter().map(|tx| (tx.source.clone(), tx.data.clone()));
469
470		let reverified_transactions = self
471			.verify(
472				at,
473				pruned_transactions,
474				CheckBannedBeforeVerify::Yes,
475				ValidateTransactionPriority::Maintained,
476			)
477			.await;
478
479		let pruned_hashes = reverified_transactions.keys().map(Clone::clone).collect::<Vec<_>>();
480		debug!(
481			target: LOG_TARGET,
482			?at,
483			reverified_transactions = reverified_transactions.len(),
484			duration = ?now.elapsed(),
485			"Pruned. Resubmitting transactions."
486		);
487		log_xt_trace!(data: tuple, target: LOG_TARGET, &reverified_transactions, "Resubmitting transaction: {:?}");
488
489		// And finally - submit reverified transactions back to the pool
490		self.validated_pool.resubmit_pruned(
491			&at,
492			known_imported_hashes,
493			pruned_hashes,
494			reverified_transactions.into_values().collect(),
495		)
496	}
497
498	/// Returns transaction hash
499	pub fn hash_of(&self, xt: &RawExtrinsicFor<B>) -> ExtrinsicHash<B> {
500		self.validated_pool.api().hash_and_length(xt).0
501	}
502
503	/// Returns future that validates a bunch of transactions at given block.
504	#[instrument(level = Level::TRACE, skip_all, target = "txpool",name = "pool::verify")]
505	async fn verify(
506		&self,
507		at: &HashAndNumber<B::Block>,
508		xts: impl IntoIterator<Item = (base::TimedTransactionSource, ExtrinsicFor<B>)>,
509		check: CheckBannedBeforeVerify,
510		validation_priority: ValidateTransactionPriority,
511	) -> IndexMap<ExtrinsicHash<B>, ValidatedTransactionFor<B>> {
512		let HashAndNumber { number, hash } = *at;
513
514		let res = futures::future::join_all(xts.into_iter().map(|(source, xt)| {
515			self.verify_one(hash, number, source, xt, check, validation_priority)
516		}))
517		.await
518		.into_iter()
519		.collect::<IndexMap<_, _>>();
520
521		res
522	}
523
524	/// Returns future that validates single transaction at given block.
525	#[instrument(level = Level::TRACE, skip_all, target = "txpool",name = "pool::verify_one")]
526	pub(crate) async fn verify_one(
527		&self,
528		block_hash: <B::Block as BlockT>::Hash,
529		block_number: NumberFor<B>,
530		source: base::TimedTransactionSource,
531		xt: ExtrinsicFor<B>,
532		check: CheckBannedBeforeVerify,
533		validation_priority: ValidateTransactionPriority,
534	) -> (ExtrinsicHash<B>, ValidatedTransactionFor<B>) {
535		let (hash, bytes) = self.validated_pool.api().hash_and_length(&xt);
536
537		let ignore_banned = matches!(check, CheckBannedBeforeVerify::No);
538		if let Err(err) = self.validated_pool.check_is_known(&hash, ignore_banned) {
539			return (hash, ValidatedTransaction::Invalid(hash, err));
540		}
541
542		let validation_result = self
543			.validated_pool
544			.api()
545			.validate_transaction(
546				block_hash,
547				source.clone().into(),
548				xt.clone(),
549				validation_priority,
550			)
551			.await;
552
553		let status = match validation_result {
554			Ok(status) => status,
555			Err(e) => return (hash, ValidatedTransaction::Invalid(hash, e)),
556		};
557
558		let validity = match status {
559			Ok(validity) => {
560				if validity.provides.is_empty() {
561					ValidatedTransaction::Invalid(hash, error::Error::NoTagsProvided.into())
562				} else {
563					ValidatedTransaction::valid_at(
564						block_number.saturated_into::<u64>(),
565						hash,
566						source,
567						xt,
568						bytes,
569						validity,
570					)
571				}
572			},
573			Err(TransactionValidityError::Invalid(e)) => {
574				ValidatedTransaction::Invalid(hash, error::Error::InvalidTransaction(e).into())
575			},
576			Err(TransactionValidityError::Unknown(e)) => {
577				ValidatedTransaction::Unknown(hash, error::Error::UnknownTransaction(e).into())
578			},
579		};
580
581		(hash, validity)
582	}
583
584	/// Get a reference to the underlying validated pool.
585	pub fn validated_pool(&self) -> &ValidatedPool<B, L> {
586		&self.validated_pool
587	}
588
589	/// Clears the recently pruned transactions in validated pool.
590	pub fn clear_recently_pruned(&mut self) {
591		self.validated_pool.pool.write().clear_recently_pruned();
592	}
593}
594
595impl<B: ChainApi, L: EventHandler<B>> Pool<B, L> {
596	/// Deep clones the pool.
597	///
598	/// Must be called on purpose: it duplicates all the internal structures.
599	pub fn deep_clone_with_event_handler(&self, event_handler: L) -> Self {
600		let other: ValidatedPool<B, L> =
601			self.validated_pool().deep_clone_with_event_handler(event_handler);
602		Self { validated_pool: Arc::from(other) }
603	}
604}
605
606#[cfg(test)]
607mod tests {
608	use super::{super::base_pool::Limit, *};
609	use crate::common::tests::{pool, uxt, TestApi, INVALID_NONCE};
610	use assert_matches::assert_matches;
611	use base::TimedTransactionSource;
612	use codec::Encode;
613	use futures::executor::block_on;
614	use parking_lot::Mutex;
615	use sc_transaction_pool_api::TransactionStatus;
616	use sp_runtime::transaction_validity::TransactionSource;
617	use std::{collections::HashMap, time::Instant};
618	use substrate_test_runtime::{AccountId, ExtrinsicBuilder, Transfer, H256};
619	use substrate_test_runtime_client::Sr25519Keyring::{Alice, Bob};
620
621	const SOURCE: TimedTransactionSource =
622		TimedTransactionSource { source: TransactionSource::External, timestamp: None };
623
624	type Pool<Api> = super::Pool<Api, ()>;
625
626	#[test]
627	fn should_validate_and_import_transaction() {
628		// given
629		let (pool, api) = pool();
630
631		// when
632		let hash = block_on(
633			pool.submit_one(
634				&api.expect_hash_and_number(0),
635				SOURCE,
636				uxt(Transfer {
637					from: Alice.into(),
638					to: AccountId::from_h256(H256::from_low_u64_be(2)),
639					amount: 5,
640					nonce: 0,
641				})
642				.into(),
643			),
644		)
645		.map(|outcome| outcome.hash())
646		.unwrap();
647
648		// then
649		assert_eq!(pool.validated_pool().ready().map(|v| v.hash).collect::<Vec<_>>(), vec![hash]);
650	}
651
652	#[test]
653	fn submit_at_preserves_order() {
654		sp_tracing::try_init_simple();
655		// given
656		let (pool, api) = pool();
657
658		let txs = (0..10)
659			.map(|i| {
660				uxt(Transfer {
661					from: Alice.into(),
662					to: AccountId::from_h256(H256::from_low_u64_be(i)),
663					amount: 5,
664					nonce: i,
665				})
666				.into()
667			})
668			.collect::<Vec<_>>();
669
670		let initial_hashes = txs.iter().map(|t| api.hash_and_length(t).0).collect::<Vec<_>>();
671
672		// when
673		let txs = txs.into_iter().map(|x| (SOURCE, Arc::from(x))).collect::<Vec<_>>();
674		let hashes = block_on(pool.submit_at(
675			&api.expect_hash_and_number(0),
676			txs,
677			ValidateTransactionPriority::Submitted,
678		))
679		.into_iter()
680		.map(|r| r.map(|o| o.hash()))
681		.collect::<Vec<_>>();
682		debug!(hashes = ?hashes, "-->");
683
684		// then
685		hashes.into_iter().zip(initial_hashes.into_iter()).for_each(
686			|(result_hash, initial_hash)| {
687				assert_eq!(result_hash.unwrap(), initial_hash);
688			},
689		);
690	}
691
692	#[test]
693	fn should_reject_if_temporarily_banned() {
694		// given
695		let (pool, api) = pool();
696		let uxt = uxt(Transfer {
697			from: Alice.into(),
698			to: AccountId::from_h256(H256::from_low_u64_be(2)),
699			amount: 5,
700			nonce: 0,
701		});
702
703		// when
704		pool.validated_pool.ban(
705			&Instant::now(),
706			vec![pool.hash_of(&uxt)],
707			crate::graph::rotator::BanReason::Validation,
708		);
709		let res = block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.into()))
710			.map(|o| o.hash());
711		assert_eq!(pool.validated_pool().status().ready, 0);
712		assert_eq!(pool.validated_pool().status().future, 0);
713
714		// then
715		assert_matches!(res.unwrap_err(), error::Error::TemporarilyBanned);
716	}
717
718	#[test]
719	fn should_reject_unactionable_transactions() {
720		// given
721		let api = Arc::new(TestApi::default());
722		let pool = Pool::new_with_staticly_sized_rotator(
723			Default::default(),
724			// the node does not author blocks
725			false.into(),
726			api.clone(),
727		);
728
729		// after validation `IncludeData` will be set to non-propagable (validate_transaction mock)
730		let uxt = ExtrinsicBuilder::new_include_data(vec![42]).build();
731
732		// when
733		let res = block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.into()))
734			.map(|o| o.hash());
735
736		// then
737		assert_matches!(res.unwrap_err(), error::Error::Unactionable);
738	}
739
740	#[test]
741	fn should_notify_about_pool_events() {
742		let (stream, hash0, hash1) = {
743			// given
744			let (pool, api) = pool();
745			let han_of_block0 = api.expect_hash_and_number(0);
746			let stream = pool.validated_pool().import_notification_stream();
747
748			// when
749			let hash0 = block_on(
750				pool.submit_one(
751					&han_of_block0,
752					SOURCE,
753					uxt(Transfer {
754						from: Alice.into(),
755						to: AccountId::from_h256(H256::from_low_u64_be(2)),
756						amount: 5,
757						nonce: 0,
758					})
759					.into(),
760				),
761			)
762			.unwrap()
763			.hash();
764			let hash1 = block_on(
765				pool.submit_one(
766					&han_of_block0,
767					SOURCE,
768					uxt(Transfer {
769						from: Alice.into(),
770						to: AccountId::from_h256(H256::from_low_u64_be(2)),
771						amount: 5,
772						nonce: 1,
773					})
774					.into(),
775				),
776			)
777			.unwrap()
778			.hash();
779			// future doesn't count
780			let _hash = block_on(
781				pool.submit_one(
782					&han_of_block0,
783					SOURCE,
784					uxt(Transfer {
785						from: Alice.into(),
786						to: AccountId::from_h256(H256::from_low_u64_be(2)),
787						amount: 5,
788						nonce: 3,
789					})
790					.into(),
791				),
792			)
793			.unwrap()
794			.hash();
795
796			assert_eq!(pool.validated_pool().status().ready, 2);
797			assert_eq!(pool.validated_pool().status().future, 1);
798
799			(stream, hash0, hash1)
800		};
801
802		// then
803		let mut it = futures::executor::block_on_stream(stream);
804		assert_eq!(it.next(), Some(hash0));
805		assert_eq!(it.next(), Some(hash1));
806		assert_eq!(it.next(), None);
807	}
808
809	#[test]
810	fn should_clear_stale_transactions() {
811		// given
812		let (pool, api) = pool();
813		let han_of_block0 = api.expect_hash_and_number(0);
814		let hash1 = block_on(
815			pool.submit_one(
816				&han_of_block0,
817				SOURCE,
818				uxt(Transfer {
819					from: Alice.into(),
820					to: AccountId::from_h256(H256::from_low_u64_be(2)),
821					amount: 5,
822					nonce: 0,
823				})
824				.into(),
825			),
826		)
827		.unwrap()
828		.hash();
829		let hash2 = block_on(
830			pool.submit_one(
831				&han_of_block0,
832				SOURCE,
833				uxt(Transfer {
834					from: Alice.into(),
835					to: AccountId::from_h256(H256::from_low_u64_be(2)),
836					amount: 5,
837					nonce: 1,
838				})
839				.into(),
840			),
841		)
842		.unwrap()
843		.hash();
844		let hash3 = block_on(
845			pool.submit_one(
846				&han_of_block0,
847				SOURCE,
848				uxt(Transfer {
849					from: Alice.into(),
850					to: AccountId::from_h256(H256::from_low_u64_be(2)),
851					amount: 5,
852					nonce: 3,
853				})
854				.into(),
855			),
856		)
857		.unwrap()
858		.hash();
859
860		// when
861		pool.validated_pool.clear_stale(&api.expect_hash_and_number(5));
862
863		// then
864		assert_eq!(pool.validated_pool().ready().count(), 0);
865		assert_eq!(pool.validated_pool().status().future, 0);
866		assert_eq!(pool.validated_pool().status().ready, 0);
867		// make sure they are temporarily banned as well
868		assert!(pool.validated_pool.is_banned(&hash1));
869		assert!(pool.validated_pool.is_banned(&hash2));
870		assert!(pool.validated_pool.is_banned(&hash3));
871	}
872
873	#[test]
874	fn should_ban_mined_transactions() {
875		// given
876		let (pool, api) = pool();
877		let hash1 = block_on(
878			pool.submit_one(
879				&api.expect_hash_and_number(0),
880				SOURCE,
881				uxt(Transfer {
882					from: Alice.into(),
883					to: AccountId::from_h256(H256::from_low_u64_be(2)),
884					amount: 5,
885					nonce: 0,
886				})
887				.into(),
888			),
889		)
890		.unwrap()
891		.hash();
892
893		// when
894		block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![vec![0]], vec![hash1]));
895
896		// then
897		assert!(pool.validated_pool.is_banned(&hash1));
898	}
899
900	#[test]
901	fn should_limit_futures() {
902		sp_tracing::try_init_simple();
903
904		let xt = uxt(Transfer {
905			from: Alice.into(),
906			to: AccountId::from_h256(H256::from_low_u64_be(2)),
907			amount: 5,
908			nonce: 1,
909		});
910
911		// given
912		let limit = Limit { count: 100, total_bytes: xt.encoded_size() };
913
914		let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
915
916		let api = Arc::new(TestApi::default());
917		let pool = Pool::new_with_staticly_sized_rotator(options, true.into(), api.clone());
918
919		let hash1 = block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt.into()))
920			.unwrap()
921			.hash();
922		assert_eq!(pool.validated_pool().status().future, 1);
923
924		// when
925		let hash2 = block_on(
926			pool.submit_one(
927				&api.expect_hash_and_number(0),
928				SOURCE,
929				uxt(Transfer {
930					from: Bob.into(),
931					to: AccountId::from_h256(H256::from_low_u64_be(2)),
932					amount: 5,
933					nonce: 10,
934				})
935				.into(),
936			),
937		)
938		.unwrap()
939		.hash();
940
941		// then
942		assert_eq!(pool.validated_pool().status().future, 1);
943		assert!(pool.validated_pool.is_banned(&hash1));
944		assert!(!pool.validated_pool.is_banned(&hash2));
945	}
946
947	#[test]
948	fn should_error_if_reject_immediately() {
949		// given
950		let limit = Limit { count: 100, total_bytes: 10 };
951
952		let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
953
954		let api = Arc::new(TestApi::default());
955		let pool = Pool::new_with_staticly_sized_rotator(options, true.into(), api.clone());
956
957		// when
958		block_on(
959			pool.submit_one(
960				&api.expect_hash_and_number(0),
961				SOURCE,
962				uxt(Transfer {
963					from: Alice.into(),
964					to: AccountId::from_h256(H256::from_low_u64_be(2)),
965					amount: 5,
966					nonce: 1,
967				})
968				.into(),
969			),
970		)
971		.map(|o| o.hash())
972		.unwrap_err();
973
974		// then
975		assert_eq!(pool.validated_pool().status().ready, 0);
976		assert_eq!(pool.validated_pool().status().future, 0);
977	}
978
979	#[test]
980	fn should_reject_transactions_with_no_provides() {
981		// given
982		let (pool, api) = pool();
983
984		// when
985		let err = block_on(
986			pool.submit_one(
987				&api.expect_hash_and_number(0),
988				SOURCE,
989				uxt(Transfer {
990					from: Alice.into(),
991					to: AccountId::from_h256(H256::from_low_u64_be(2)),
992					amount: 5,
993					nonce: INVALID_NONCE,
994				})
995				.into(),
996			),
997		)
998		.map(|o| o.hash())
999		.unwrap_err();
1000
1001		// then
1002		assert_eq!(pool.validated_pool().status().ready, 0);
1003		assert_eq!(pool.validated_pool().status().future, 0);
1004		assert_matches!(err, error::Error::NoTagsProvided);
1005	}
1006
1007	mod listener {
1008		use super::*;
1009
1010		#[test]
1011		fn should_trigger_ready_and_in_block_when_pruning_via_hash() {
1012			// given
1013			let (pool, api) = pool();
1014			let watcher = block_on(
1015				pool.submit_and_watch(
1016					&api.expect_hash_and_number(0),
1017					SOURCE,
1018					uxt(Transfer {
1019						from: Alice.into(),
1020						to: AccountId::from_h256(H256::from_low_u64_be(2)),
1021						amount: 5,
1022						nonce: 0,
1023					})
1024					.into(),
1025				),
1026			)
1027			.unwrap()
1028			.expect_watcher();
1029			assert_eq!(pool.validated_pool().status().ready, 1);
1030			assert_eq!(pool.validated_pool().status().future, 0);
1031
1032			let han_of_block2 = api.expect_hash_and_number(2);
1033
1034			// when
1035			block_on(pool.prune_tags(&han_of_block2, vec![vec![0u8]], vec![*watcher.hash()]));
1036			assert_eq!(pool.validated_pool().status().ready, 0);
1037			assert_eq!(pool.validated_pool().status().future, 0);
1038
1039			// then
1040			let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1041			assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1042			assert_eq!(
1043				stream.next(),
1044				Some(TransactionStatus::InBlock((han_of_block2.hash.into(), 0))),
1045			);
1046		}
1047
1048		#[test]
1049		fn should_trigger_future_and_ready_after_promoted() {
1050			// given
1051			let (pool, api) = pool();
1052			let han_of_block0 = api.expect_hash_and_number(0);
1053
1054			let watcher = block_on(
1055				pool.submit_and_watch(
1056					&han_of_block0,
1057					SOURCE,
1058					uxt(Transfer {
1059						from: Alice.into(),
1060						to: AccountId::from_h256(H256::from_low_u64_be(2)),
1061						amount: 5,
1062						nonce: 1,
1063					})
1064					.into(),
1065				),
1066			)
1067			.unwrap()
1068			.expect_watcher();
1069			assert_eq!(pool.validated_pool().status().ready, 0);
1070			assert_eq!(pool.validated_pool().status().future, 1);
1071
1072			// when
1073			block_on(
1074				pool.submit_one(
1075					&han_of_block0,
1076					SOURCE,
1077					uxt(Transfer {
1078						from: Alice.into(),
1079						to: AccountId::from_h256(H256::from_low_u64_be(2)),
1080						amount: 5,
1081						nonce: 0,
1082					})
1083					.into(),
1084				),
1085			)
1086			.unwrap();
1087			assert_eq!(pool.validated_pool().status().ready, 2);
1088
1089			// then
1090			let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1091			assert_eq!(stream.next(), Some(TransactionStatus::Future));
1092			assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1093		}
1094
1095		#[test]
1096		fn should_trigger_invalid_and_ban() {
1097			// given
1098			let (pool, api) = pool();
1099			let uxt = uxt(Transfer {
1100				from: Alice.into(),
1101				to: AccountId::from_h256(H256::from_low_u64_be(2)),
1102				amount: 5,
1103				nonce: 0,
1104			});
1105			let watcher =
1106				block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, uxt.into()))
1107					.unwrap()
1108					.expect_watcher();
1109			assert_eq!(pool.validated_pool().status().ready, 1);
1110
1111			// when
1112			pool.validated_pool.remove_invalid(&[*watcher.hash()]);
1113
1114			// then
1115			let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1116			assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1117			assert_eq!(stream.next(), Some(TransactionStatus::Invalid));
1118			assert_eq!(stream.next(), None);
1119		}
1120
1121		#[test]
1122		fn should_trigger_broadcasted() {
1123			// given
1124			let (pool, api) = pool();
1125			let uxt = uxt(Transfer {
1126				from: Alice.into(),
1127				to: AccountId::from_h256(H256::from_low_u64_be(2)),
1128				amount: 5,
1129				nonce: 0,
1130			});
1131			let watcher =
1132				block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, uxt.into()))
1133					.unwrap()
1134					.expect_watcher();
1135			assert_eq!(pool.validated_pool().status().ready, 1);
1136
1137			// when
1138			let mut map = HashMap::new();
1139			let peers = vec!["a".into(), "b".into(), "c".into()];
1140			map.insert(*watcher.hash(), peers.clone());
1141			pool.validated_pool().on_broadcasted(map);
1142
1143			// then
1144			let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1145			assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1146			assert_eq!(stream.next(), Some(TransactionStatus::Broadcast(peers)));
1147		}
1148
1149		#[test]
1150		fn should_trigger_dropped_older() {
1151			// given
1152			let limit = Limit { count: 1, total_bytes: 1000 };
1153			let options =
1154				Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
1155
1156			let api = Arc::new(TestApi::default());
1157			let pool = Pool::new_with_staticly_sized_rotator(options, true.into(), api.clone());
1158
1159			let xt = uxt(Transfer {
1160				from: Alice.into(),
1161				to: AccountId::from_h256(H256::from_low_u64_be(2)),
1162				amount: 5,
1163				nonce: 0,
1164			});
1165			let watcher =
1166				block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, xt.into()))
1167					.unwrap()
1168					.expect_watcher();
1169			assert_eq!(pool.validated_pool().status().ready, 1);
1170
1171			// when
1172			let xt = uxt(Transfer {
1173				from: Bob.into(),
1174				to: AccountId::from_h256(H256::from_low_u64_be(1)),
1175				amount: 4,
1176				nonce: 1,
1177			});
1178			block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into())).unwrap();
1179			assert_eq!(pool.validated_pool().status().ready, 1);
1180
1181			// then
1182			let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1183			assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1184			assert_eq!(stream.next(), Some(TransactionStatus::Dropped));
1185		}
1186
1187		#[test]
1188		fn should_trigger_dropped_lower_priority() {
1189			{
1190				// given
1191				let limit = Limit { count: 1, total_bytes: 1000 };
1192				let options =
1193					Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
1194
1195				let api = Arc::new(TestApi::default());
1196				let pool = Pool::new_with_staticly_sized_rotator(options, true.into(), api.clone());
1197
1198				// after validation `IncludeData` will have priority set to 9001
1199				// (validate_transaction mock)
1200				let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
1201				block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt.into()))
1202					.unwrap();
1203				assert_eq!(pool.validated_pool().status().ready, 1);
1204
1205				// then
1206				// after validation `Transfer` will have priority set to 4 (validate_transaction
1207				// mock)
1208				let xt = uxt(Transfer {
1209					from: Bob.into(),
1210					to: AccountId::from_h256(H256::from_low_u64_be(1)),
1211					amount: 4,
1212					nonce: 1,
1213				});
1214				let result =
1215					block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into()));
1216				assert!(matches!(
1217					result,
1218					Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped)
1219				));
1220			}
1221			{
1222				// given
1223				let limit = Limit { count: 2, total_bytes: 1000 };
1224				let options =
1225					Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
1226
1227				let api = Arc::new(TestApi::default());
1228				let pool = Pool::new_with_staticly_sized_rotator(options, true.into(), api.clone());
1229
1230				let han_of_block0 = api.expect_hash_and_number(0);
1231
1232				// after validation `IncludeData` will have priority set to 9001
1233				// (validate_transaction mock)
1234				let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
1235				block_on(pool.submit_and_watch(&han_of_block0, SOURCE, xt.into()))
1236					.unwrap()
1237					.expect_watcher();
1238				assert_eq!(pool.validated_pool().status().ready, 1);
1239
1240				// after validation `Transfer` will have priority set to 4 (validate_transaction
1241				// mock)
1242				let xt = uxt(Transfer {
1243					from: Alice.into(),
1244					to: AccountId::from_h256(H256::from_low_u64_be(2)),
1245					amount: 5,
1246					nonce: 0,
1247				});
1248				let watcher = block_on(pool.submit_and_watch(&han_of_block0, SOURCE, xt.into()))
1249					.unwrap()
1250					.expect_watcher();
1251				assert_eq!(pool.validated_pool().status().ready, 2);
1252
1253				// when
1254				// after validation `Store` will have priority set to 9001 (validate_transaction
1255				// mock)
1256				let xt = ExtrinsicBuilder::new_indexed_call(Vec::new()).build();
1257				block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into()))
1258					.unwrap();
1259				assert_eq!(pool.validated_pool().status().ready, 2);
1260
1261				// then
1262				let mut stream = futures::executor::block_on_stream(watcher.into_stream());
1263				assert_eq!(stream.next(), Some(TransactionStatus::Ready));
1264				assert_eq!(stream.next(), Some(TransactionStatus::Dropped));
1265			}
1266		}
1267
1268		#[test]
1269		fn should_handle_pruning_in_the_middle_of_import() {
1270			// given
1271			let (ready, is_ready) = std::sync::mpsc::sync_channel(0);
1272			let (tx, rx) = std::sync::mpsc::sync_channel(1);
1273			let mut api = TestApi::default();
1274			api.delay = Arc::new(Mutex::new(rx.into()));
1275			let api = Arc::new(api);
1276			let pool = Arc::new(Pool::new_with_staticly_sized_rotator(
1277				Default::default(),
1278				true.into(),
1279				api.clone(),
1280			));
1281
1282			let han_of_block0 = api.expect_hash_and_number(0);
1283
1284			// when
1285			let xt = uxt(Transfer {
1286				from: Alice.into(),
1287				to: AccountId::from_h256(H256::from_low_u64_be(2)),
1288				amount: 5,
1289				nonce: 1,
1290			});
1291
1292			// This transaction should go to future, since we use `nonce: 1`
1293			let pool2 = pool.clone();
1294			std::thread::spawn({
1295				let hash_of_block0 = han_of_block0.clone();
1296				move || {
1297					block_on(pool2.submit_one(&hash_of_block0, SOURCE, xt.into())).unwrap();
1298					ready.send(()).unwrap();
1299				}
1300			});
1301
1302			// But now before the previous one is imported we import
1303			// the one that it depends on.
1304			let xt = uxt(Transfer {
1305				from: Alice.into(),
1306				to: AccountId::from_h256(H256::from_low_u64_be(2)),
1307				amount: 4,
1308				nonce: 0,
1309			});
1310			// The tag the above transaction provides (TestApi is using just nonce as u8)
1311			let provides = vec![0_u8];
1312			block_on(pool.submit_one(&han_of_block0, SOURCE, xt.into())).unwrap();
1313			assert_eq!(pool.validated_pool().status().ready, 1);
1314
1315			// Now block import happens before the second transaction is able to finish
1316			// verification.
1317			block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![provides], vec![]));
1318			assert_eq!(pool.validated_pool().status().ready, 0);
1319
1320			// so when we release the verification of the previous one it will have
1321			// something in `requires`, but should go to ready directly, since the previous
1322			// transaction was imported correctly.
1323			tx.send(()).unwrap();
1324
1325			// then
1326			is_ready.recv().unwrap(); // wait for finish
1327			assert_eq!(pool.validated_pool().status().ready, 1);
1328			assert_eq!(pool.validated_pool().status().future, 0);
1329		}
1330	}
1331}