mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 08:07:58 +00:00
Revalidation queue for transaction pool (#4781)
* Revalidation queeue. * add docs and license * move test * refactor worker to async/await * address review * fix warnings * update Cargo.lock * move background task to service * use tomusdrw loop * naming * return From::from * add doc comment * add more doc comments * fix merge bug * add doc comment for test function * Update client/transaction-pool/src/testing/pool.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * more review fixes * refactor to allow service keep background tasks from isntantiated subsystems * use const delay * fix fallout * remove fallout * remove already moved test * fix doc test * add valid_at helper Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
use futures::executor::block_on;
|
||||
use txpool::{self, Pool};
|
||||
use sp_runtime::{
|
||||
@@ -22,18 +23,22 @@ use sp_runtime::{
|
||||
transaction_validity::ValidTransaction,
|
||||
};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{Block, Hash, Index, Header},
|
||||
runtime::{Block, Hash, Index, Header, Extrinsic},
|
||||
AccountKeyring::*,
|
||||
};
|
||||
use substrate_test_runtime_transaction_pool::{TestApi, uxt};
|
||||
use sp_transaction_pool::TransactionStatus;
|
||||
use crate::revalidation::BACKGROUND_REVALIDATION_INTERVAL;
|
||||
|
||||
fn pool() -> Pool<TestApi> {
|
||||
Pool::new(Default::default(), TestApi::with_alice_nonce(209).into())
|
||||
}
|
||||
|
||||
fn maintained_pool() -> BasicPool<TestApi, Block> {
|
||||
BasicPool::new(Default::default(), std::sync::Arc::new(TestApi::with_alice_nonce(209)))
|
||||
fn maintained_pool() -> (BasicPool<TestApi, Block>, futures::executor::ThreadPool) {
|
||||
let (pool, background_task) = BasicPool::new(Default::default(), std::sync::Arc::new(TestApi::with_alice_nonce(209)));
|
||||
|
||||
let thread_pool = futures::executor::ThreadPool::new().unwrap();
|
||||
thread_pool.spawn_ok(background_task.expect("basic pool have background task"));
|
||||
(pool, thread_pool)
|
||||
}
|
||||
|
||||
fn header(number: u64) -> Header {
|
||||
@@ -158,25 +163,37 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
|
||||
assert_eq!(pool.validated_pool().status().future, 2);
|
||||
}
|
||||
|
||||
fn block_event(id: u64) -> ChainEvent<Block> {
|
||||
ChainEvent::NewBlock {
|
||||
id: BlockId::number(id),
|
||||
is_new_best: true,
|
||||
retracted: vec![],
|
||||
header: header(id),
|
||||
}
|
||||
}
|
||||
|
||||
fn block_event_with_retracted(id: u64, retracted: Vec<Hash>) -> ChainEvent<Block> {
|
||||
ChainEvent::NewBlock {
|
||||
id: BlockId::number(id),
|
||||
is_new_best: true,
|
||||
retracted: retracted,
|
||||
header: header(id),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn should_prune_old_during_maintenance() {
|
||||
let xt = uxt(Alice, 209);
|
||||
|
||||
let pool = maintained_pool();
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![xt.clone()]);
|
||||
|
||||
let event = ChainEvent::NewBlock {
|
||||
id: BlockId::number(1),
|
||||
is_new_best: true,
|
||||
retracted: vec![],
|
||||
header: header(1),
|
||||
};
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
}
|
||||
|
||||
@@ -185,21 +202,20 @@ fn should_revalidate_during_maintenance() {
|
||||
let xt1 = uxt(Alice, 209);
|
||||
let xt2 = uxt(Alice, 210);
|
||||
|
||||
let pool = maintained_pool();
|
||||
let (pool, _guard) = maintained_pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt1.clone())).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt2.clone())).expect("2. Imported");
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
assert_eq!(pool.api.validation_requests().len(), 2);
|
||||
|
||||
pool.api.push_block(1, vec![xt1.clone()]);
|
||||
let event = ChainEvent::NewBlock {
|
||||
id: BlockId::number(1),
|
||||
is_new_best: true,
|
||||
retracted: vec![],
|
||||
header: header(1),
|
||||
};
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
|
||||
// maintaince is in background
|
||||
block_on(futures_timer::Delay::new(BACKGROUND_REVALIDATION_INTERVAL*2));
|
||||
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
// test that pool revalidated transaction that left ready and not included in the block
|
||||
assert_eq!(pool.api.validation_requests().len(), 3);
|
||||
@@ -210,19 +226,15 @@ fn should_resubmit_from_retracted_during_maintaince() {
|
||||
let xt = uxt(Alice, 209);
|
||||
let retracted_hash = Hash::random();
|
||||
|
||||
let pool = maintained_pool();
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
|
||||
pool.api.push_block(1, vec![]);
|
||||
pool.api.push_fork_block(retracted_hash, vec![xt.clone()]);
|
||||
let event = ChainEvent::NewBlock {
|
||||
id: BlockId::Number(1),
|
||||
is_new_best: true,
|
||||
header: header(1),
|
||||
retracted: vec![retracted_hash]
|
||||
};
|
||||
|
||||
let event = block_event_with_retracted(1, vec![retracted_hash]);
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
@@ -233,7 +245,7 @@ fn should_not_retain_invalid_hashes_from_retracted() {
|
||||
let xt = uxt(Alice, 209);
|
||||
let retracted_hash = Hash::random();
|
||||
|
||||
let pool = maintained_pool();
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
@@ -242,20 +254,90 @@ fn should_not_retain_invalid_hashes_from_retracted() {
|
||||
pool.api.push_fork_block(retracted_hash, vec![xt.clone()]);
|
||||
pool.api.add_invalid(&xt);
|
||||
|
||||
let event = ChainEvent::NewBlock {
|
||||
id: BlockId::Number(1),
|
||||
is_new_best: true,
|
||||
header: header(1),
|
||||
retracted: vec![retracted_hash]
|
||||
};
|
||||
let event = block_event_with_retracted(1, vec![retracted_hash]);
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
|
||||
// maintenance is in background
|
||||
block_on(futures_timer::Delay::new(BACKGROUND_REVALIDATION_INTERVAL*2));
|
||||
|
||||
let event = block_event_with_retracted(1, vec![retracted_hash]);
|
||||
|
||||
block_on(pool.maintain(event));
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_push_watchers_during_maintaince() {
|
||||
fn alice_uxt(nonce: u64) -> Extrinsic {
|
||||
uxt(Alice, 209 + nonce)
|
||||
}
|
||||
|
||||
// given
|
||||
let (pool, _guard) = maintained_pool();
|
||||
|
||||
let tx0 = alice_uxt(0);
|
||||
let watcher0 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx0.clone())).unwrap();
|
||||
let tx1 = alice_uxt(1);
|
||||
let watcher1 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx1.clone())).unwrap();
|
||||
let tx2 = alice_uxt(2);
|
||||
let watcher2 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx2.clone())).unwrap();
|
||||
let tx3 = alice_uxt(3);
|
||||
let watcher3 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx3.clone())).unwrap();
|
||||
let tx4 = alice_uxt(4);
|
||||
let watcher4 = block_on(pool.submit_and_watch(&BlockId::Number(0), tx4.clone())).unwrap();
|
||||
assert_eq!(pool.status().ready, 5);
|
||||
|
||||
// when
|
||||
pool.api.add_invalid(&tx3);
|
||||
pool.api.add_invalid(&tx4);
|
||||
block_on(pool.maintain(block_event(0)));
|
||||
|
||||
// revalidation is in background
|
||||
block_on(futures_timer::Delay::new(BACKGROUND_REVALIDATION_INTERVAL*2));
|
||||
|
||||
// then
|
||||
// hash3 is now invalid
|
||||
// hash4 is now invalid
|
||||
|
||||
assert_eq!(pool.status().ready, 3);
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher3).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::Invalid],
|
||||
);
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher4).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::Invalid],
|
||||
);
|
||||
|
||||
// when
|
||||
let header_hash = pool.api.push_block(1, vec![tx0, tx1, tx2]).hash();
|
||||
block_on(pool.maintain(block_event(1)));
|
||||
|
||||
let event = ChainEvent::Finalized { hash: header_hash.clone() };
|
||||
block_on(pool.maintain(event));
|
||||
|
||||
// then
|
||||
// events for hash0 are: Ready, InBlock
|
||||
// events for hash1 are: Ready, InBlock
|
||||
// events for hash2 are: Ready, InBlock
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher0).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::InBlock(header_hash.clone()), TransactionStatus::Finalized(header_hash.clone())],
|
||||
);
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher1).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::InBlock(header_hash.clone()), TransactionStatus::Finalized(header_hash.clone())],
|
||||
);
|
||||
assert_eq!(
|
||||
futures::executor::block_on_stream(watcher2).collect::<Vec<_>>(),
|
||||
vec![TransactionStatus::Ready, TransactionStatus::InBlock(header_hash.clone()), TransactionStatus::Finalized(header_hash.clone())],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_track_heap_size() {
|
||||
let pool = maintained_pool();
|
||||
let (pool, _guard) = maintained_pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 209))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 210))).expect("1. Imported");
|
||||
block_on(pool.submit_one(&BlockId::number(0), uxt(Alice, 211))).expect("1. Imported");
|
||||
@@ -269,7 +351,7 @@ fn finalization() {
|
||||
let xt = uxt(Alice, 209);
|
||||
let api = TestApi::with_alice_nonce(209);
|
||||
api.push_block(1, vec![]);
|
||||
let pool = BasicPool::new(Default::default(), api.into());
|
||||
let (pool, _background) = BasicPool::new(Default::default(), api.into());
|
||||
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), xt.clone())).expect("1. Imported");
|
||||
pool.api.push_block(2, vec![xt.clone()]);
|
||||
|
||||
@@ -298,7 +380,7 @@ fn fork_aware_finalization() {
|
||||
// starting block A1 (last finalized.)
|
||||
api.push_block(1, vec![]);
|
||||
|
||||
let pool = BasicPool::new(Default::default(), api.into());
|
||||
let (pool, _background) = BasicPool::new(Default::default(), api.into());
|
||||
let mut canon_watchers = vec![];
|
||||
|
||||
let from_alice = uxt(Alice, 1);
|
||||
|
||||
Reference in New Issue
Block a user