diff --git a/substrate/core/transaction-pool/graph/src/error.rs b/substrate/core/transaction-pool/graph/src/error.rs index 07e0324354..ce457c0179 100644 --- a/substrate/core/transaction-pool/graph/src/error.rs +++ b/substrate/core/transaction-pool/graph/src/error.rs @@ -30,6 +30,12 @@ pub enum Error { /// Transaction is invalid. #[display(fmt="Invalid Transaction. Error Code: {}", _0)] InvalidTransaction(i8), + /// The transaction validity returned no "provides" tag. + /// + /// Such transactions are not accepted to the pool, since we use those tags + /// to define identity of transactions (occupance of the same "slot"). + #[display(fmt="The transaction does not provide any tags, so the pool can't identify it.")] + NoTagsProvided, /// The transaction is temporarily banned. #[display(fmt="Temporarily Banned")] TemporarilyBanned, diff --git a/substrate/core/transaction-pool/graph/src/pool.rs b/substrate/core/transaction-pool/graph/src/pool.rs index 06159257ae..07542afab0 100644 --- a/substrate/core/transaction-pool/graph/src/pool.rs +++ b/substrate/core/transaction-pool/graph/src/pool.rs @@ -129,7 +129,9 @@ impl Pool { } match self.api.validate_transaction(at, xt.clone())? { - TransactionValidity::Valid(validity) => { + TransactionValidity::Valid(validity) => if validity.provides.is_empty() { + Err(error::Error::NoTagsProvided.into()) + } else { Ok(base::Transaction { data: xt, bytes @@ -458,6 +460,8 @@ mod tests { use assert_matches::assert_matches; use crate::watcher; + const INVALID_NONCE: u64 = 254; + #[derive(Debug, Default)] struct TestApi { delay: Mutex>>, @@ -490,7 +494,7 @@ mod tests { Ok(TransactionValidity::Valid(ValidTransaction { priority: 4, requires: if nonce > block_number { vec![vec![nonce as u8 - 1]] } else { vec![] }, - provides: vec![vec![nonce as u8]], + provides: if nonce == INVALID_NONCE { vec![] } else { vec![vec![nonce as u8]] }, longevity: 3, propagate: true, })) @@ -723,6 +727,24 @@ mod tests { assert_eq!(pool.status().future, 0); } + #[test] + fn should_reject_transactions_with_no_provides() { + // given + let pool = pool(); + + // when + let err = pool.submit_one(&BlockId::Number(0), uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: INVALID_NONCE, + })).unwrap_err(); + + // then + assert_eq!(pool.status().ready, 0); + assert_eq!(pool.status().future, 0); + assert_matches!(err, error::Error::NoTagsProvided); + } mod listener { use super::*;