mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 21:37:56 +00:00
Adds fork-awareness and finalization notifications to transaction pool watchers. (#4740)
* adds finalization support to sc-transaction-pool using MaintainedTransactionPool for finalization events * adds TransactionStatus::Retracted, notify watchers of retracted blocks, finalized now finalizes, transactions for current finalized -> last finalized block * adds last_finalized to ChainApi, use generic BlockT for ChainEvent * fix tests * Apply suggestions from code review Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * tests * fix tests, docs, lazily dedupe pruned hashes * fix tests, Cargo.lock * Apply suggestions from code review Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * remove tree_route, last_finalized from ChainApi, add block hash to Finalization and Retracted events * prune finality watchers * fix tests * remove HeaderBackend bound from FullChainApi * code style nits, terminate stream in finality_timeout Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
@@ -33,7 +33,7 @@ use sp_runtime::{
|
||||
traits::{self, SaturatedConversion},
|
||||
transaction_validity::{TransactionValidity, TransactionTag as Tag, TransactionValidityError},
|
||||
};
|
||||
use sp_transaction_pool::{error, PoolStatus};
|
||||
use sp_transaction_pool::error;
|
||||
use wasm_timer::Instant;
|
||||
|
||||
use crate::validated_pool::{ValidatedPool, ValidatedTransaction};
|
||||
@@ -338,34 +338,6 @@ impl<B: ChainApi> Pool<B> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Return an event stream of notifications for when transactions are imported to the pool.
|
||||
///
|
||||
/// Consumers of this stream should use the `ready` method to actually get the
|
||||
/// pending transactions in the right order.
|
||||
pub fn import_notification_stream(&self) -> EventStream<ExHash<B>> {
|
||||
self.validated_pool.import_notification_stream()
|
||||
}
|
||||
|
||||
/// Invoked when extrinsics are broadcasted.
|
||||
pub fn on_broadcasted(&self, propagated: HashMap<ExHash<B>, Vec<String>>) {
|
||||
self.validated_pool.on_broadcasted(propagated)
|
||||
}
|
||||
|
||||
/// Remove invalid transactions from the pool.
|
||||
pub fn remove_invalid(&self, hashes: &[ExHash<B>]) -> Vec<TransactionFor<B>> {
|
||||
self.validated_pool.remove_invalid(hashes)
|
||||
}
|
||||
|
||||
/// Get an iterator for ready transactions ordered by priority
|
||||
pub fn ready(&self) -> impl Iterator<Item=TransactionFor<B>> {
|
||||
self.validated_pool.ready()
|
||||
}
|
||||
|
||||
/// Returns pool status.
|
||||
pub fn status(&self) -> PoolStatus {
|
||||
self.validated_pool.status()
|
||||
}
|
||||
|
||||
/// Returns transaction hash
|
||||
pub fn hash_of(&self, xt: &ExtrinsicFor<B>) -> ExHash<B> {
|
||||
self.validated_pool.api().hash_and_length(xt).0
|
||||
@@ -454,9 +426,9 @@ impl<B: ChainApi> Pool<B> {
|
||||
(hash, validity)
|
||||
}
|
||||
|
||||
/// Get ready transaction by hash, if it present in the pool.
|
||||
pub fn ready_transaction(&self, hash: &ExHash<B>) -> Option<TransactionFor<B>> {
|
||||
self.validated_pool.ready_by_hash(hash)
|
||||
/// get a reference to the underlying validated pool.
|
||||
pub fn validated_pool(&self) -> &ValidatedPool<B> {
|
||||
&self.validated_pool
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +570,7 @@ mod tests {
|
||||
}))).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(pool.ready().map(|v| v.hash).collect::<Vec<_>>(), vec![hash]);
|
||||
assert_eq!(pool.validated_pool().ready().map(|v| v.hash).collect::<Vec<_>>(), vec![hash]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -615,8 +587,8 @@ mod tests {
|
||||
// when
|
||||
pool.validated_pool.rotator().ban(&Instant::now(), vec![pool.hash_of(&uxt)]);
|
||||
let res = block_on(pool.submit_one(&BlockId::Number(0), uxt));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
// then
|
||||
assert_matches!(res.unwrap_err(), error::Error::TemporarilyBanned);
|
||||
@@ -627,7 +599,7 @@ mod tests {
|
||||
let stream = {
|
||||
// given
|
||||
let pool = pool();
|
||||
let stream = pool.import_notification_stream();
|
||||
let stream = pool.validated_pool().import_notification_stream();
|
||||
|
||||
// when
|
||||
let _hash = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
@@ -650,8 +622,8 @@ mod tests {
|
||||
nonce: 3,
|
||||
}))).unwrap();
|
||||
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.status().future, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 2);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
stream
|
||||
};
|
||||
|
||||
@@ -689,9 +661,9 @@ mod tests {
|
||||
pool.validated_pool.clear_stale(&BlockId::Number(5)).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(pool.ready().count(), 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().ready().count(), 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
// make sure they are temporarily banned as well
|
||||
assert!(pool.validated_pool.rotator().is_banned(&hash1));
|
||||
assert!(pool.validated_pool.rotator().is_banned(&hash2));
|
||||
@@ -735,7 +707,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
}))).unwrap();
|
||||
assert_eq!(pool.status().future, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
|
||||
// when
|
||||
let hash2 = block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
@@ -746,7 +718,7 @@ mod tests {
|
||||
}))).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(pool.status().future, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
assert!(pool.validated_pool.rotator().is_banned(&hash1));
|
||||
assert!(!pool.validated_pool.rotator().is_banned(&hash2));
|
||||
}
|
||||
@@ -773,8 +745,8 @@ mod tests {
|
||||
}))).unwrap_err();
|
||||
|
||||
// then
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -791,8 +763,8 @@ mod tests {
|
||||
}))).unwrap_err();
|
||||
|
||||
// then
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
assert_matches!(err, error::Error::NoTagsProvided);
|
||||
}
|
||||
|
||||
@@ -809,19 +781,18 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}))).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
// when
|
||||
block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![])).unwrap();
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
// then
|
||||
let mut stream = futures::executor::block_on_stream(watcher.into_stream());
|
||||
assert_eq!(stream.next(), Some(TransactionStatus::Ready));
|
||||
assert_eq!(stream.next(), Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())));
|
||||
assert_eq!(stream.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -834,19 +805,18 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}))).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
// when
|
||||
block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![2u64])).unwrap();
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
|
||||
// then
|
||||
let mut stream = futures::executor::block_on_stream(watcher.into_stream());
|
||||
assert_eq!(stream.next(), Some(TransactionStatus::Ready));
|
||||
assert_eq!(stream.next(), Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())));
|
||||
assert_eq!(stream.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -859,8 +829,8 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
}))).unwrap();
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.status().future, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
|
||||
// when
|
||||
block_on(pool.submit_one(&BlockId::Number(0), uxt(Transfer {
|
||||
@@ -869,7 +839,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}))).unwrap();
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.validated_pool().status().ready, 2);
|
||||
|
||||
// then
|
||||
let mut stream = futures::executor::block_on_stream(watcher.into_stream());
|
||||
@@ -888,7 +858,7 @@ mod tests {
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt)).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
pool.validated_pool.remove_invalid(&[*watcher.hash()]);
|
||||
@@ -912,13 +882,13 @@ mod tests {
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), uxt)).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
let mut map = HashMap::new();
|
||||
let peers = vec!["a".into(), "b".into(), "c".into()];
|
||||
map.insert(*watcher.hash(), peers.clone());
|
||||
pool.on_broadcasted(map);
|
||||
pool.validated_pool().on_broadcasted(map);
|
||||
|
||||
|
||||
// then
|
||||
@@ -947,7 +917,7 @@ mod tests {
|
||||
nonce: 0,
|
||||
});
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), xt)).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// when
|
||||
let xt = uxt(Transfer {
|
||||
@@ -957,7 +927,7 @@ mod tests {
|
||||
nonce: 1,
|
||||
});
|
||||
block_on(pool.submit_one(&BlockId::Number(1), xt)).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// then
|
||||
let mut stream = futures::executor::block_on_stream(watcher.into_stream());
|
||||
@@ -1000,11 +970,11 @@ mod tests {
|
||||
// The tag the above transaction provides (TestApi is using just nonce as u8)
|
||||
let provides = vec![0_u8];
|
||||
block_on(pool.submit_one(&BlockId::Number(0), xt)).unwrap();
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// Now block import happens before the second transaction is able to finish verification.
|
||||
block_on(pool.prune_tags(&BlockId::Number(1), vec![provides], vec![])).unwrap();
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 0);
|
||||
|
||||
|
||||
// so when we release the verification of the previous one it will have
|
||||
@@ -1014,8 +984,8 @@ mod tests {
|
||||
|
||||
// then
|
||||
is_ready.recv().unwrap(); // wait for finish
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
assert_eq!(pool.status().future, 0);
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,7 +1017,7 @@ mod tests {
|
||||
let tx4 = transfer(4);
|
||||
let hash4 = pool.validated_pool.api().hash_and_length(&tx4).0;
|
||||
let watcher4 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx4)).unwrap();
|
||||
assert_eq!(pool.status().ready, 5);
|
||||
assert_eq!(pool.validated_pool().status().ready, 5);
|
||||
|
||||
// when
|
||||
pool.validated_pool.api().invalidate.lock().insert(hash3);
|
||||
@@ -1064,7 +1034,7 @@ mod tests {
|
||||
//
|
||||
// events for hash3 are: Ready, Invalid
|
||||
// events for hash4 are: Ready, Invalid
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.validated_pool().status().ready, 2);
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher3.into_stream()).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::Invalid],
|
||||
@@ -1095,4 +1065,3 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user