Fix tx-pool returning the same transaction multiple times (#6535)

* Fix tx-pool returning the same transaction multiple times

This fixes a bug that lead to returning the same transaction multiple
times when iterating the `ready` iterator. Internally the transaction
was kept in the `best` list and could be duplicated in that list be
re-inserting it again. This `best` list is using a `TransactionRef`
which internally uses a `insertion_id`. This `insertion_id` could lead
to the same transaction being inserted multiple times into the `best`
list.

* Update client/transaction-pool/src/testing/pool.rs

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
Bastian Köcher
2020-06-30 11:02:46 +02:00
committed by GitHub
parent 5a925ecc7e
commit 493d5d8591
5 changed files with 63 additions and 24 deletions
+12 -2
View File
@@ -194,10 +194,20 @@ impl sp_runtime::traits::Dispatchable for Extrinsic {
}
impl Extrinsic {
/// Convert `&self` into `&Transfer`.
///
/// Panics if this is no `Transfer` extrinsic.
pub fn transfer(&self) -> &Transfer {
self.try_transfer().expect("cannot convert to transfer ref")
}
/// Try to convert `&self` into `&Transfer`.
///
/// Returns `None` if this is no `Transfer` extrinsic.
pub fn try_transfer(&self) -> Option<&Transfer> {
match self {
Extrinsic::Transfer { ref transfer, .. } => transfer,
_ => panic!("cannot convert to transfer ref"),
Extrinsic::Transfer { ref transfer, .. } => Some(transfer),
_ => None,
}
}
}
@@ -209,13 +209,19 @@ impl sc_transaction_graph::ChainApi for TestApi {
) -> Self::ValidationFuture {
self.validation_requests.write().push(uxt.clone());
let chain_nonce = self.chain.read().nonces.get(&uxt.transfer().from).cloned().unwrap_or(0);
let requires = if chain_nonce == uxt.transfer().nonce {
vec![]
let (requires, provides) = if let Some(transfer) = uxt.try_transfer() {
let chain_nonce = self.chain.read().nonces.get(&transfer.from).cloned().unwrap_or(0);
let requires = if chain_nonce == transfer.nonce {
vec![]
} else {
vec![vec![chain_nonce as u8]]
};
let provides = vec![vec![transfer.nonce as u8]];
(requires, provides)
} else {
vec![vec![chain_nonce as u8]]
(Vec::new(), vec![uxt.encode()])
};
let provides = vec![vec![uxt.transfer().nonce as u8]];
if self.chain.read().invalid_hashes.contains(&self.hash_and_length(&uxt).0) {
return futures::future::ready(Ok(