BlockId removal: tx-pool refactor (#1678)

It changes following APIs:
- trait `ChainApi`
-- `validate_transaction`

- trait `TransactionPool` 
--`submit_at`
--`submit_one`
--`submit_and_watch`

and some implementation details, in particular:
- impl `Pool` 
--`submit_at`
--`resubmit_at`
--`submit_one`
--`submit_and_watch`
--`prune_known`
--`prune`
--`prune_tags`
--`resolve_block_number`
--`verify`
--`verify_one`

- revalidation queue

All tests are also adjusted.

---------

Co-authored-by: command-bot <>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Michal Kucharczyk
2023-09-27 11:58:39 +02:00
committed by GitHub
parent a846b74604
commit ab3a3bc278
20 changed files with 609 additions and 460 deletions
@@ -21,7 +21,7 @@ use cumulus_test_runtime::{AccountId, BalancesCall, ExistentialDeposit, SudoCall
use futures::{future, StreamExt};
use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus};
use sp_core::{crypto::Pair, sr25519};
use sp_runtime::{generic::BlockId, OpaqueExtrinsic};
use sp_runtime::OpaqueExtrinsic;
use cumulus_primitives_core::ParaId;
use cumulus_test_service::{
@@ -117,7 +117,7 @@ async fn submit_tx_and_wait_for_inclusion(
let best_hash = client.chain_info().best_hash;
let mut watch = tx_pool
.submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone())
.submit_and_watch(best_hash, TransactionSource::External, tx.clone())
.await
.expect("Submits tx to pool")
.fuse();
+4 -4
View File
@@ -35,7 +35,7 @@ use sc_transaction_pool_api::{
};
use sp_consensus::{Environment, Proposer};
use sp_inherents::InherentDataProvider;
use sp_runtime::{generic::BlockId, traits::NumberFor, OpaqueExtrinsic};
use sp_runtime::{traits::NumberFor, OpaqueExtrinsic};
use crate::{
common::SizeType,
@@ -233,7 +233,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
/// Returns a future that imports a bunch of unverified transactions to the pool.
fn submit_at(
&self,
_at: &BlockId<Self::Block>,
_at: Self::Hash,
_source: TransactionSource,
_xts: Vec<TransactionFor<Self>>,
) -> PoolFuture<Vec<Result<node_primitives::Hash, Self::Error>>, Self::Error> {
@@ -243,7 +243,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
/// Returns a future that imports one unverified transaction to the pool.
fn submit_one(
&self,
_at: &BlockId<Self::Block>,
_at: Self::Hash,
_source: TransactionSource,
_xt: TransactionFor<Self>,
) -> PoolFuture<TxHash<Self>, Self::Error> {
@@ -252,7 +252,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions {
fn submit_and_watch(
&self,
_at: &BlockId<Self::Block>,
_at: Self::Hash,
_source: TransactionSource,
_xt: TransactionFor<Self>,
) -> PoolFuture<Pin<Box<TransactionStatusStreamFor<Self>>>, Self::Error> {
+3 -3
View File
@@ -27,7 +27,6 @@ use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes};
use sc_transaction_pool::BasicPool;
use sc_transaction_pool_api::{TransactionPool, TransactionSource};
use sp_runtime::generic::BlockId;
use crate::core::{self, Mode, Path};
@@ -58,10 +57,11 @@ impl core::BenchmarkDescription for PoolBenchmarkDescription {
impl core::Benchmark for PoolBenchmark {
fn run(&mut self, mode: Mode) -> std::time::Duration {
let context = self.database.create_context();
let genesis_hash = context.client.chain_info().genesis_hash;
let _ = context
.client
.runtime_version_at(context.client.chain_info().genesis_hash)
.runtime_version_at(genesis_hash)
.expect("Failed to get runtime version")
.spec_version;
@@ -90,7 +90,7 @@ impl core::Benchmark for PoolBenchmark {
let start = std::time::Instant::now();
let submissions = generated_transactions
.into_iter()
.map(|tx| txpool.submit_one(&BlockId::Number(0), TransactionSource::External, tx));
.map(|tx| txpool.submit_one(genesis_hash, TransactionSource::External, tx));
futures::executor::block_on(futures::future::join_all(submissions));
let elapsed = start.elapsed();
@@ -34,7 +34,7 @@ use sc_transaction_pool::PoolLimit;
use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus};
use sp_core::{crypto::Pair, sr25519};
use sp_keyring::Sr25519Keyring;
use sp_runtime::{generic::BlockId, OpaqueExtrinsic};
use sp_runtime::OpaqueExtrinsic;
use tokio::runtime::Handle;
fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
@@ -191,7 +191,7 @@ async fn submit_tx_and_wait_for_inclusion(
let best_hash = client.chain_info().best_hash;
let mut watch = tx_pool
.submit_and_watch(&BlockId::Hash(best_hash), TransactionSource::External, tx.clone())
.submit_and_watch(best_hash, TransactionSource::External, tx.clone())
.await
.expect("Submits tx to pool")
.fuse();
@@ -642,8 +642,8 @@ mod tests {
client.clone(),
);
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0), extrinsic(1)]))
.unwrap();
let hashof0 = client.info().genesis_hash;
block_on(txpool.submit_at(hashof0, SOURCE, vec![extrinsic(0), extrinsic(1)])).unwrap();
block_on(
txpool.maintain(chain_event(
@@ -658,7 +658,7 @@ mod tests {
let cell = Mutex::new((false, time::Instant::now()));
let proposer = proposer_factory.init_with_now(
&client.expect_header(client.info().genesis_hash).unwrap(),
&client.expect_header(hashof0).unwrap(),
Box::new(move || {
let mut value = cell.lock();
if !value.0 {
@@ -736,7 +736,7 @@ mod tests {
let genesis_hash = client.info().best_hash;
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, vec![extrinsic(0)])).unwrap();
block_on(txpool.submit_at(genesis_hash, SOURCE, vec![extrinsic(0)])).unwrap();
block_on(
txpool.maintain(chain_event(
@@ -800,7 +800,7 @@ mod tests {
};
block_on(txpool.submit_at(
&BlockId::number(0),
client.info().genesis_hash,
SOURCE,
vec![medium(0), medium(1), huge(2), medium(3), huge(4), medium(5), medium(6)],
))
@@ -897,9 +897,8 @@ mod tests {
spawner.clone(),
client.clone(),
);
let genesis_header = client
.expect_header(client.info().genesis_hash)
.expect("there should be header");
let genesis_hash = client.info().genesis_hash;
let genesis_header = client.expect_header(genesis_hash).expect("there should be header");
let extrinsics_num = 5;
let extrinsics = std::iter::once(
@@ -922,7 +921,7 @@ mod tests {
.sum::<usize>() +
Vec::<Extrinsic>::new().encoded_size();
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics.clone())).unwrap();
block_on(txpool.submit_at(genesis_hash, SOURCE, extrinsics.clone())).unwrap();
block_on(txpool.maintain(chain_event(genesis_header.clone())));
@@ -999,6 +998,7 @@ mod tests {
spawner.clone(),
client.clone(),
);
let genesis_hash = client.info().genesis_hash;
let tiny = |nonce| {
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)).nonce(nonce).build()
@@ -1011,7 +1011,7 @@ mod tests {
block_on(
txpool.submit_at(
&BlockId::number(0),
genesis_hash,
SOURCE,
// add 2 * MAX_SKIPPED_TRANSACTIONS that exhaust resources
(0..MAX_SKIPPED_TRANSACTIONS * 2)
@@ -1024,13 +1024,9 @@ mod tests {
)
.unwrap();
block_on(
txpool.maintain(chain_event(
client
.expect_header(client.info().genesis_hash)
.expect("there should be header"),
)),
);
block_on(txpool.maintain(chain_event(
client.expect_header(genesis_hash).expect("there should be header"),
)));
assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 3);
let mut proposer_factory =
@@ -1038,7 +1034,7 @@ mod tests {
let cell = Mutex::new(time::Instant::now());
let proposer = proposer_factory.init_with_now(
&client.expect_header(client.info().genesis_hash).unwrap(),
&client.expect_header(genesis_hash).unwrap(),
Box::new(move || {
let mut value = cell.lock();
let old = *value;
@@ -1071,6 +1067,7 @@ mod tests {
spawner.clone(),
client.clone(),
);
let genesis_hash = client.info().genesis_hash;
let tiny = |who| {
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY))
@@ -1086,7 +1083,7 @@ mod tests {
block_on(
txpool.submit_at(
&BlockId::number(0),
genesis_hash,
SOURCE,
(0..MAX_SKIPPED_TRANSACTIONS + 2)
.into_iter()
@@ -1098,13 +1095,9 @@ mod tests {
)
.unwrap();
block_on(
txpool.maintain(chain_event(
client
.expect_header(client.info().genesis_hash)
.expect("there should be header"),
)),
);
block_on(txpool.maintain(chain_event(
client.expect_header(genesis_hash).expect("there should be header"),
)));
assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 2 + 4);
let mut proposer_factory =
@@ -1114,7 +1107,7 @@ mod tests {
let cell = Arc::new(Mutex::new((0, time::Instant::now())));
let cell2 = cell.clone();
let proposer = proposer_factory.init_with_now(
&client.expect_header(client.info().genesis_hash).unwrap(),
&client.expect_header(genesis_hash).unwrap(),
Box::new(move || {
let mut value = cell.lock();
let (called, old) = *value;
@@ -351,7 +351,7 @@ mod tests {
use sc_transaction_pool::{BasicPool, FullChainApi, Options, RevalidationType};
use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource};
use sp_inherents::InherentData;
use sp_runtime::generic::{BlockId, Digest, DigestItem};
use sp_runtime::generic::{Digest, DigestItem};
use substrate_test_runtime_client::{
AccountKeyring::*, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
@@ -400,10 +400,11 @@ mod tests {
let client = Arc::new(client);
let spawner = sp_core::testing::TaskExecutor::new();
let genesis_hash = client.info().genesis_hash;
let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone()));
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(),
true.into(),
api(),
pool_api,
None,
RevalidationType::Full,
spawner.clone(),
@@ -444,7 +445,7 @@ mod tests {
rt.block_on(future);
});
// submit a transaction to pool.
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await;
// assert that it was successfully imported
assert!(result.is_ok());
// assert that the background task returns ok
@@ -475,10 +476,11 @@ mod tests {
let client = Arc::new(client);
let spawner = sp_core::testing::TaskExecutor::new();
let genesis_hash = client.info().genesis_hash;
let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone()));
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(),
true.into(),
api(),
pool_api,
None,
RevalidationType::Full,
spawner.clone(),
@@ -535,7 +537,7 @@ mod tests {
let mut finality_stream = client.finality_notification_stream();
// submit a transaction to pool.
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await;
// assert that it was successfully imported
assert!(result.is_ok());
// assert that the background task returns ok
@@ -571,10 +573,11 @@ mod tests {
let client = Arc::new(client);
let spawner = sp_core::testing::TaskExecutor::new();
let genesis_hash = client.info().genesis_hash;
let pool_api = Arc::new(FullChainApi::new(client.clone(), None, &spawner.clone()));
let pool = Arc::new(BasicPool::with_revalidation_type(
Options::default(),
true.into(),
api(),
pool_api,
None,
RevalidationType::Full,
spawner.clone(),
@@ -602,7 +605,7 @@ mod tests {
rt.block_on(future);
});
// submit a transaction to pool.
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await;
// assert that it was successfully imported
assert!(result.is_ok());
let (tx, rx) = futures::channel::oneshot::channel();
@@ -688,7 +691,7 @@ mod tests {
rt.block_on(future);
});
// submit a transaction to pool.
let result = pool.submit_one(&BlockId::Number(0), SOURCE, uxt(Alice, 0)).await;
let result = pool.submit_one(genesis_hash, SOURCE, uxt(Alice, 0)).await;
// assert that it was successfully imported
assert!(result.is_ok());
@@ -719,7 +722,7 @@ mod tests {
}
);
assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 1)).await.is_ok());
assert!(pool.submit_one(created_block.hash, SOURCE, uxt(Alice, 1)).await.is_ok());
let header = client.header(created_block.hash).expect("db error").expect("imported above");
assert_eq!(header.number, 1);
@@ -741,7 +744,7 @@ mod tests {
.is_ok());
assert_matches::assert_matches!(rx1.await.expect("should be no error receiving"), Ok(_));
assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Bob, 0)).await.is_ok());
assert!(pool.submit_one(created_block.hash, SOURCE, uxt(Bob, 0)).await.is_ok());
let (tx2, rx2) = futures::channel::oneshot::channel();
assert!(sink
.send(EngineCommand::SealNewBlock {
@@ -46,7 +46,7 @@ use std::sync::Arc;
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::Bytes;
use sp_runtime::{generic, traits::Block as BlockT};
use sp_runtime::traits::Block as BlockT;
use codec::Decode;
use futures::{FutureExt, StreamExt, TryFutureExt};
@@ -110,11 +110,7 @@ where
let submit = self
.pool
.submit_and_watch(
&generic::BlockId::hash(best_block_hash),
TX_SOURCE,
decoded_extrinsic,
)
.submit_and_watch(best_block_hash, TX_SOURCE, decoded_extrinsic)
.map_err(|e| {
e.into_pool_error()
.map(Error::from)
+12 -18
View File
@@ -41,7 +41,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_blockchain::HeaderBackend;
use sp_core::Bytes;
use sp_keystore::{KeystoreExt, KeystorePtr};
use sp_runtime::{generic, traits::Block as BlockT};
use sp_runtime::traits::Block as BlockT;
use sp_session::SessionKeys;
use self::error::{Error, Result};
@@ -97,15 +97,12 @@ where
Err(err) => return Err(Error::Client(Box::new(err)).into()),
};
let best_block_hash = self.client.info().best_hash;
self.pool
.submit_one(&generic::BlockId::hash(best_block_hash), TX_SOURCE, xt)
.await
.map_err(|e| {
e.into_pool_error()
.map(|e| Error::Pool(e))
.unwrap_or_else(|e| Error::Verification(Box::new(e)))
.into()
})
self.pool.submit_one(best_block_hash, TX_SOURCE, xt).await.map_err(|e| {
e.into_pool_error()
.map(|e| Error::Pool(e))
.unwrap_or_else(|e| Error::Verification(Box::new(e)))
.into()
})
}
fn insert_key(&self, key_type: String, suri: String, public: Bytes) -> RpcResult<()> {
@@ -191,14 +188,11 @@ where
},
};
let submit = self
.pool
.submit_and_watch(&generic::BlockId::hash(best_block_hash), TX_SOURCE, dxt)
.map_err(|e| {
e.into_pool_error()
.map(error::Error::from)
.unwrap_or_else(|e| error::Error::Verification(Box::new(e)))
});
let submit = self.pool.submit_and_watch(best_block_hash, TX_SOURCE, dxt).map_err(|e| {
e.into_pool_error()
.map(error::Error::from)
.unwrap_or_else(|e| error::Error::Verification(Box::new(e)))
});
let fut = async move {
let stream = match submit.await {
+4 -10
View File
@@ -48,10 +48,7 @@ use sc_network_sync::SyncingService;
use sc_utils::mpsc::TracingUnboundedReceiver;
use sp_blockchain::HeaderMetadata;
use sp_consensus::SyncOracle;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT},
};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
pub use self::{
builder::{
@@ -481,10 +478,8 @@ where
},
};
let best_block_id = BlockId::hash(self.client.info().best_hash);
let import_future = self.pool.submit_one(
&best_block_id,
self.client.info().best_hash,
sc_transaction_pool_api::TransactionSource::External,
uxt,
);
@@ -549,10 +544,9 @@ mod tests {
to: AccountKeyring::Bob.into(),
}
.into_unchecked_extrinsic();
block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone()))
.unwrap();
block_on(pool.submit_one(best.hash(), source, transaction.clone())).unwrap();
block_on(pool.submit_one(
&BlockId::hash(best.hash()),
best.hash(),
source,
ExtrinsicBuilder::new_call_do_not_propagate().nonce(1).build(),
))
+4 -7
View File
@@ -34,7 +34,6 @@ use sc_service::{
RuntimeGenesis, SpawnTaskHandle, TaskManager,
};
use sc_transaction_pool_api::TransactionPool;
use sp_api::BlockId;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use std::{iter, net::Ipv4Addr, pin::Pin, sync::Arc, task::Context, time::Duration};
@@ -501,15 +500,13 @@ pub fn sync<G, E, Fb, F, B, ExF, U>(
info!("Checking extrinsic propagation");
let first_service = network.full_nodes[0].1.clone();
let first_user_data = &network.full_nodes[0].2;
let best_block = BlockId::number(first_service.client().info().best_number);
let best_block = first_service.client().info().best_hash;
let extrinsic = extrinsic_factory(&first_service, first_user_data);
let source = sc_transaction_pool_api::TransactionSource::External;
futures::executor::block_on(first_service.transaction_pool().submit_one(
&best_block,
source,
extrinsic,
))
futures::executor::block_on(
first_service.transaction_pool().submit_one(best_block, source, extrinsic),
)
.expect("failed to submit extrinsic");
network.run_until_all_full(|_index, service| service.transaction_pool().ready().count() == 1);
@@ -26,10 +26,7 @@ use codec::Codec;
use futures::{Future, Stream};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sp_core::offchain::TransactionPoolExt;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Member, NumberFor},
};
use sp_runtime::traits::{Block as BlockT, Member, NumberFor};
use std::{collections::HashMap, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc};
const LOG_TARGET: &str = "txpool::api";
@@ -202,7 +199,7 @@ pub trait TransactionPool: Send + Sync {
/// Returns a future that imports a bunch of unverified transactions to the pool.
fn submit_at(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xts: Vec<TransactionFor<Self>>,
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error>;
@@ -210,7 +207,7 @@ pub trait TransactionPool: Send + Sync {
/// Returns a future that imports one unverified transaction to the pool.
fn submit_one(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<TxHash<Self>, Self::Error>;
@@ -219,7 +216,7 @@ pub trait TransactionPool: Send + Sync {
/// pool.
fn submit_and_watch(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<Pin<Box<TransactionStatusStreamFor<Self>>>, Self::Error>;
@@ -33,6 +33,7 @@ use sp_runtime::{
ValidTransaction,
},
};
use std::sync::Arc;
use substrate_test_runtime::{AccountId, Block, Extrinsic, ExtrinsicBuilder, TransferData, H256};
#[derive(Clone, Debug, Default)]
@@ -61,7 +62,7 @@ impl ChainApi for TestApi {
fn validate_transaction(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
_source: TransactionSource,
uxt: <Self::Block as BlockT>::Extrinsic,
) -> Self::ValidationFuture {
@@ -70,7 +71,7 @@ impl ChainApi for TestApi {
let nonce = transfer.nonce;
let from = transfer.from;
match self.block_id_to_number(at) {
match self.block_id_to_number(&BlockId::Hash(at)) {
Ok(Some(num)) if num > 5 => return ready(Ok(Err(InvalidTransaction::Stale.into()))),
_ => {},
}
@@ -94,6 +95,8 @@ impl ChainApi for TestApi {
) -> Result<Option<NumberFor<Self::Block>>, Self::Error> {
Ok(match at {
BlockId::Number(num) => Some(*num),
BlockId::Hash(hash) if *hash == H256::from_low_u64_be(hash.to_low_u64_be()) =>
Some(hash.to_low_u64_be()),
BlockId::Hash(_) => None,
})
}
@@ -104,7 +107,7 @@ impl ChainApi for TestApi {
) -> Result<Option<<Self::Block as BlockT>::Hash>, Self::Error> {
Ok(match at {
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(),
BlockId::Hash(_) => None,
BlockId::Hash(hash) => Some(*hash),
})
}
@@ -137,7 +140,7 @@ fn uxt(transfer: TransferData) -> Extrinsic {
ExtrinsicBuilder::new_bench_call(transfer).build()
}
fn bench_configured(pool: Pool<TestApi>, number: u64) {
fn bench_configured(pool: Pool<TestApi>, number: u64, api: Arc<TestApi>) {
let source = TransactionSource::External;
let mut futures = Vec::new();
let mut tags = Vec::new();
@@ -151,7 +154,12 @@ fn bench_configured(pool: Pool<TestApi>, number: u64) {
});
tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1))));
futures.push(pool.submit_one(&BlockId::Number(1), source, xt));
futures.push(pool.submit_one(
api.block_id_to_hash(&BlockId::Number(1)).unwrap().unwrap(),
source,
xt,
));
}
let res = block_on(futures::future::join_all(futures.into_iter()));
@@ -162,7 +170,12 @@ fn bench_configured(pool: Pool<TestApi>, number: u64) {
// Prune all transactions.
let block_num = 6;
block_on(pool.prune_tags(&BlockId::Number(block_num), tags, vec![])).expect("Prune failed");
block_on(pool.prune_tags(
api.block_id_to_hash(&BlockId::Number(block_num)).unwrap().unwrap(),
tags,
vec![],
))
.expect("Prune failed");
// pool is empty
assert_eq!(pool.validated_pool().status().ready, 0);
@@ -172,19 +185,15 @@ fn bench_configured(pool: Pool<TestApi>, number: u64) {
fn benchmark_main(c: &mut Criterion) {
c.bench_function("sequential 50 tx", |b| {
b.iter(|| {
bench_configured(
Pool::new(Default::default(), true.into(), TestApi::new_dependant().into()),
50,
);
let api = Arc::from(TestApi::new_dependant());
bench_configured(Pool::new(Default::default(), true.into(), api.clone()), 50, api);
});
});
c.bench_function("random 100 tx", |b| {
b.iter(|| {
bench_configured(
Pool::new(Default::default(), true.into(), TestApi::default().into()),
100,
);
let api = Arc::from(TestApi::default());
bench_configured(Pool::new(Default::default(), true.into(), api.clone()), 100, api);
});
});
}
+11 -16
View File
@@ -133,13 +133,12 @@ where
fn validate_transaction(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
uxt: graph::ExtrinsicFor<Self>,
) -> Self::ValidationFuture {
let (tx, rx) = oneshot::channel();
let client = self.client.clone();
let at = *at;
let validation_pool = self.validation_pool.clone();
let metrics = self.metrics.clone();
@@ -151,7 +150,7 @@ where
.await
.send(
async move {
let res = validate_transaction_blocking(&*client, &at, source, uxt);
let res = validate_transaction_blocking(&*client, at, source, uxt);
let _ = tx.send(res);
metrics.report(|m| m.validations_finished.inc());
}
@@ -209,7 +208,7 @@ where
/// This method will call into the runtime to perform the validation.
fn validate_transaction_blocking<Client, Block>(
client: &Client,
at: &BlockId<Block>,
at: Block::Hash,
source: TransactionSource,
uxt: graph::ExtrinsicFor<FullChainApi<Client, Block>>,
) -> error::Result<TransactionValidity>
@@ -225,14 +224,10 @@ where
{
sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction";
{
let block_hash = client.to_hash(at)
.map_err(|e| Error::RuntimeApi(e.to_string()))?
.ok_or_else(|| Error::RuntimeApi(format!("Could not get hash for block `{:?}`.", at)))?;
let runtime_api = client.runtime_api();
let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version";
runtime_api
.api_version::<dyn TaggedTransactionQueue<Block>>(block_hash)
.api_version::<dyn TaggedTransactionQueue<Block>>(at)
.map_err(|e| Error::RuntimeApi(e.to_string()))?
.ok_or_else(|| Error::RuntimeApi(
format!("Could not find `TaggedTransactionQueue` api for block `{:?}`.", at)
@@ -245,31 +240,31 @@ where
sp_tracing::Level::TRACE, "runtime::validate_transaction";
{
if api_version >= 3 {
runtime_api.validate_transaction(block_hash, source, uxt, block_hash)
runtime_api.validate_transaction(at, source, uxt, at)
.map_err(|e| Error::RuntimeApi(e.to_string()))
} else {
let block_number = client.to_number(at)
let block_number = client.to_number(&BlockId::Hash(at))
.map_err(|e| Error::RuntimeApi(e.to_string()))?
.ok_or_else(||
Error::RuntimeApi(format!("Could not get number for block `{:?}`.", at))
)?;
// The old versions require us to call `initialize_block` before.
runtime_api.initialize_block(block_hash, &sp_runtime::traits::Header::new(
runtime_api.initialize_block(at, &sp_runtime::traits::Header::new(
block_number + sp_runtime::traits::One::one(),
Default::default(),
Default::default(),
block_hash,
at,
Default::default()),
).map_err(|e| Error::RuntimeApi(e.to_string()))?;
if api_version == 2 {
#[allow(deprecated)] // old validate_transaction
runtime_api.validate_transaction_before_version_3(block_hash, source, uxt)
runtime_api.validate_transaction_before_version_3(at, source, uxt)
.map_err(|e| Error::RuntimeApi(e.to_string()))
} else {
#[allow(deprecated)] // old validate_transaction
runtime_api.validate_transaction_before_version_2(block_hash, uxt)
runtime_api.validate_transaction_before_version_2(at, uxt)
.map_err(|e| Error::RuntimeApi(e.to_string()))
}
}
@@ -294,7 +289,7 @@ where
/// the runtime locally.
pub fn validate_transaction_blocking(
&self,
at: &BlockId<Block>,
at: Block::Hash,
source: TransactionSource,
uxt: graph::ExtrinsicFor<Self>,
) -> error::Result<TransactionValidity> {
@@ -71,7 +71,7 @@ pub trait ChainApi: Send + Sync {
/// Verify extrinsic at given block.
fn validate_transaction(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
uxt: ExtrinsicFor<Self>,
) -> Self::ValidationFuture;
@@ -154,7 +154,7 @@ impl<B: ChainApi> Pool<B> {
/// Imports a bunch of unverified extrinsics to the pool
pub async fn submit_at(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
source: TransactionSource,
xts: impl IntoIterator<Item = ExtrinsicFor<B>>,
) -> Result<Vec<Result<ExtrinsicHash<B>, B::Error>>, B::Error> {
@@ -168,7 +168,7 @@ impl<B: ChainApi> Pool<B> {
/// This does not check if a transaction is banned, before we verify it again.
pub async fn resubmit_at(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
source: TransactionSource,
xts: impl IntoIterator<Item = ExtrinsicFor<B>>,
) -> Result<Vec<Result<ExtrinsicHash<B>, B::Error>>, B::Error> {
@@ -180,7 +180,7 @@ impl<B: ChainApi> Pool<B> {
/// Imports one unverified extrinsic to the pool
pub async fn submit_one(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
source: TransactionSource,
xt: ExtrinsicFor<B>,
) -> Result<ExtrinsicHash<B>, B::Error> {
@@ -191,11 +191,11 @@ impl<B: ChainApi> Pool<B> {
/// Import a single extrinsic and starts to watch its progress in the pool.
pub async fn submit_and_watch(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
source: TransactionSource,
xt: ExtrinsicFor<B>,
) -> Result<Watcher<ExtrinsicHash<B>, ExtrinsicHash<B>>, B::Error> {
let block_number = self.resolve_block_number(at)?;
let block_number = self.resolve_block_number(&BlockId::Hash(at))?;
let (_, tx) = self
.verify_one(at, block_number, source, xt, CheckBannedBeforeVerify::Yes)
.await;
@@ -246,8 +246,8 @@ impl<B: ChainApi> Pool<B> {
/// their provided tags from there. Otherwise we query the runtime at the `parent` block.
pub async fn prune(
&self,
at: &BlockId<B::Block>,
parent: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
parent: <B::Block as BlockT>::Hash,
extrinsics: &[ExtrinsicFor<B>],
) -> Result<(), B::Error> {
log::debug!(
@@ -324,7 +324,7 @@ impl<B: ChainApi> Pool<B> {
/// prevent importing them in the (near) future.
pub async fn prune_tags(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
tags: impl IntoIterator<Item = Tag>,
known_imported_hashes: impl IntoIterator<Item = ExtrinsicHash<B>> + Clone,
) -> Result<(), B::Error> {
@@ -351,7 +351,7 @@ impl<B: ChainApi> Pool<B> {
// And finally - submit reverified transactions back to the pool
self.validated_pool.resubmit_pruned(
at,
&BlockId::Hash(at),
known_imported_hashes,
pruned_hashes,
reverified_transactions.into_values().collect(),
@@ -373,12 +373,12 @@ impl<B: ChainApi> Pool<B> {
/// Returns future that validates a bunch of transactions at given block.
async fn verify(
&self,
at: &BlockId<B::Block>,
at: <B::Block as BlockT>::Hash,
xts: impl IntoIterator<Item = (TransactionSource, ExtrinsicFor<B>)>,
check: CheckBannedBeforeVerify,
) -> Result<HashMap<ExtrinsicHash<B>, ValidatedTransactionFor<B>>, B::Error> {
// we need a block number to compute tx validity
let block_number = self.resolve_block_number(at)?;
let block_number = self.resolve_block_number(&BlockId::Hash(at))?;
let res = futures::future::join_all(
xts.into_iter()
@@ -394,7 +394,7 @@ impl<B: ChainApi> Pool<B> {
/// Returns future that validates single transaction at given block.
async fn verify_one(
&self,
block_id: &BlockId<B::Block>,
block_hash: <B::Block as BlockT>::Hash,
block_number: NumberFor<B>,
source: TransactionSource,
xt: ExtrinsicFor<B>,
@@ -410,7 +410,7 @@ impl<B: ChainApi> Pool<B> {
let validation_result = self
.validated_pool
.api()
.validate_transaction(block_id, source, xt.clone())
.validate_transaction(block_hash, source, xt.clone())
.await;
let status = match validation_result {
@@ -458,6 +458,7 @@ mod tests {
use super::{super::base_pool::Limit, *};
use crate::tests::{pool, uxt, TestApi, INVALID_NONCE};
use assert_matches::assert_matches;
use codec::Encode;
use futures::executor::block_on;
use parking_lot::Mutex;
use sc_transaction_pool_api::TransactionStatus;
@@ -471,11 +472,11 @@ mod tests {
#[test]
fn should_validate_and_import_transaction() {
// given
let pool = pool();
let (pool, api) = pool();
// when
let hash = block_on(pool.submit_one(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -493,7 +494,7 @@ mod tests {
#[test]
fn should_reject_if_temporarily_banned() {
// given
let pool = pool();
let (pool, api) = pool();
let uxt = uxt(Transfer {
from: Alice.into(),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
@@ -503,7 +504,7 @@ mod tests {
// when
pool.validated_pool.ban(&Instant::now(), vec![pool.hash_of(&uxt)]);
let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt));
let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt));
assert_eq!(pool.validated_pool().status().ready, 0);
assert_eq!(pool.validated_pool().status().future, 0);
@@ -514,18 +515,19 @@ mod tests {
#[test]
fn should_reject_unactionable_transactions() {
// given
let api = Arc::new(TestApi::default());
let pool = Pool::new(
Default::default(),
// the node does not author blocks
false.into(),
TestApi::default().into(),
api.clone(),
);
// after validation `IncludeData` will be set to non-propagable (validate_transaction mock)
let uxt = ExtrinsicBuilder::new_include_data(vec![42]).build();
// when
let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt));
let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt));
// then
assert_matches!(res.unwrap_err(), error::Error::Unactionable);
@@ -535,12 +537,13 @@ mod tests {
fn should_notify_about_pool_events() {
let (stream, hash0, hash1) = {
// given
let pool = pool();
let (pool, api) = pool();
let hash_of_block0 = api.expect_hash_from_number(0);
let stream = pool.validated_pool().import_notification_stream();
// when
let hash0 = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -551,7 +554,7 @@ mod tests {
))
.unwrap();
let hash1 = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -563,7 +566,7 @@ mod tests {
.unwrap();
// future doesn't count
let _hash = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -590,9 +593,10 @@ mod tests {
#[test]
fn should_clear_stale_transactions() {
// given
let pool = pool();
let (pool, api) = pool();
let hash_of_block0 = api.expect_hash_from_number(0);
let hash1 = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -603,7 +607,7 @@ mod tests {
))
.unwrap();
let hash2 = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -614,7 +618,7 @@ mod tests {
))
.unwrap();
let hash3 = block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -641,9 +645,9 @@ mod tests {
#[test]
fn should_ban_mined_transactions() {
// given
let pool = pool();
let (pool, api) = pool();
let hash1 = block_on(pool.submit_one(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -655,12 +659,12 @@ mod tests {
.unwrap();
// when
block_on(pool.prune_tags(&BlockId::Number(1), vec![vec![0]], vec![hash1])).unwrap();
block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![0]], vec![hash1]))
.unwrap();
// then
assert!(pool.validated_pool.is_banned(&hash1));
}
use codec::Encode;
#[test]
fn should_limit_futures() {
@@ -678,14 +682,15 @@ mod tests {
let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
let pool = Pool::new(options, true.into(), TestApi::default().into());
let api = Arc::new(TestApi::default());
let pool = Pool::new(options, true.into(), api.clone());
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
let hash1 = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().future, 1);
// when
let hash2 = block_on(pool.submit_one(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Bob.into(),
@@ -709,11 +714,12 @@ mod tests {
let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
let pool = Pool::new(options, true.into(), TestApi::default().into());
let api = Arc::new(TestApi::default());
let pool = Pool::new(options, true.into(), api.clone());
// when
block_on(pool.submit_one(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -732,11 +738,11 @@ mod tests {
#[test]
fn should_reject_transactions_with_no_provides() {
// given
let pool = pool();
let (pool, api) = pool();
// when
let err = block_on(pool.submit_one(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -759,9 +765,9 @@ mod tests {
#[test]
fn should_trigger_ready_and_finalized() {
// given
let pool = pool();
let (pool, api) = pool();
let watcher = block_on(pool.submit_and_watch(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -774,26 +780,25 @@ mod tests {
assert_eq!(pool.validated_pool().status().ready, 1);
assert_eq!(pool.validated_pool().status().future, 0);
let hash_of_block2 = api.expect_hash_from_number(2);
// when
block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![])).unwrap();
block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![])).unwrap();
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(), 0))),
);
assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),);
}
#[test]
fn should_trigger_ready_and_finalized_when_pruning_via_hash() {
// given
let pool = pool();
let (pool, api) = pool();
let watcher = block_on(pool.submit_and_watch(
&BlockId::Number(0),
api.expect_hash_from_number(0),
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -806,8 +811,10 @@ mod tests {
assert_eq!(pool.validated_pool().status().ready, 1);
assert_eq!(pool.validated_pool().status().future, 0);
let hash_of_block2 = api.expect_hash_from_number(2);
// when
block_on(pool.prune_tags(&BlockId::Number(2), vec![vec![0u8]], vec![*watcher.hash()]))
block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![*watcher.hash()]))
.unwrap();
assert_eq!(pool.validated_pool().status().ready, 0);
assert_eq!(pool.validated_pool().status().future, 0);
@@ -815,18 +822,17 @@ mod tests {
// 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(), 0))),
);
assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),);
}
#[test]
fn should_trigger_future_and_ready_after_promoted() {
// given
let pool = pool();
let (pool, api) = pool();
let hash_of_block0 = api.expect_hash_from_number(0);
let watcher = block_on(pool.submit_and_watch(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -841,7 +847,7 @@ mod tests {
// when
block_on(pool.submit_one(
&BlockId::Number(0),
hash_of_block0,
SOURCE,
uxt(Transfer {
from: Alice.into(),
@@ -862,7 +868,7 @@ mod tests {
#[test]
fn should_trigger_invalid_and_ban() {
// given
let pool = pool();
let (pool, api) = pool();
let uxt = uxt(Transfer {
from: Alice.into(),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
@@ -870,7 +876,8 @@ mod tests {
nonce: 0,
});
let watcher =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt))
.unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// when
@@ -886,7 +893,7 @@ mod tests {
#[test]
fn should_trigger_broadcasted() {
// given
let pool = pool();
let (pool, api) = pool();
let uxt = uxt(Transfer {
from: Alice.into(),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
@@ -894,7 +901,8 @@ mod tests {
nonce: 0,
});
let watcher =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, uxt)).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt))
.unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// when
@@ -916,7 +924,8 @@ mod tests {
let options =
Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
let pool = Pool::new(options, true.into(), TestApi::default().into());
let api = Arc::new(TestApi::default());
let pool = Pool::new(options, true.into(), api.clone());
let xt = uxt(Transfer {
from: Alice.into(),
@@ -924,7 +933,9 @@ mod tests {
amount: 5,
nonce: 0,
});
let watcher = block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap();
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt))
.unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// when
@@ -934,7 +945,7 @@ mod tests {
amount: 4,
nonce: 1,
});
block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// then
@@ -951,12 +962,13 @@ mod tests {
let options =
Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
let pool = Pool::new(options, true.into(), TestApi::default().into());
let api = Arc::new(TestApi::default());
let pool = Pool::new(options, true.into(), api.clone());
// after validation `IncludeData` will have priority set to 9001
// (validate_transaction mock)
let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// then
@@ -968,7 +980,7 @@ mod tests {
amount: 4,
nonce: 1,
});
let result = block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt));
let result = block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt));
assert!(matches!(
result,
Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped)
@@ -980,12 +992,15 @@ mod tests {
let options =
Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
let pool = Pool::new(options, true.into(), TestApi::default().into());
let api = Arc::new(TestApi::default());
let pool = Pool::new(options, true.into(), api.clone());
let hash_of_block0 = api.expect_hash_from_number(0);
// after validation `IncludeData` will have priority set to 9001
// (validate_transaction mock)
let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap();
block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().ready, 1);
// after validation `Transfer` will have priority set to 4 (validate_transaction
@@ -996,15 +1011,14 @@ mod tests {
amount: 5,
nonce: 0,
});
let watcher =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap();
let watcher = block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().ready, 2);
// when
// after validation `Store` will have priority set to 9001 (validate_transaction
// mock)
let xt = ExtrinsicBuilder::new_indexed_call(Vec::new()).build();
block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap();
assert_eq!(pool.validated_pool().status().ready, 2);
// then
@@ -1021,7 +1035,10 @@ mod tests {
let (tx, rx) = std::sync::mpsc::sync_channel(1);
let mut api = TestApi::default();
api.delay = Arc::new(Mutex::new(rx.into()));
let pool = Arc::new(Pool::new(Default::default(), true.into(), api.into()));
let api = Arc::new(api);
let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone()));
let hash_of_block0 = api.expect_hash_from_number(0);
// when
let xt = uxt(Transfer {
@@ -1034,7 +1051,7 @@ mod tests {
// This transaction should go to future, since we use `nonce: 1`
let pool2 = pool.clone();
std::thread::spawn(move || {
block_on(pool2.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
block_on(pool2.submit_one(hash_of_block0, SOURCE, xt)).unwrap();
ready.send(()).unwrap();
});
@@ -1048,12 +1065,13 @@ 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), SOURCE, xt)).unwrap();
block_on(pool.submit_one(hash_of_block0, SOURCE, xt)).unwrap();
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();
block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![provides], vec![]))
.unwrap();
assert_eq!(pool.validated_pool().status().ready, 0);
// so when we release the verification of the previous one it will have
+20 -24
View File
@@ -166,8 +166,11 @@ where
finalized_hash: Block::Hash,
) -> (Self, Pin<Box<dyn Future<Output = ()> + Send>>) {
let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone()));
let (revalidation_queue, background_task) =
revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone());
let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background(
pool_api.clone(),
pool.clone(),
finalized_hash,
);
(
Self {
api: pool_api,
@@ -203,8 +206,11 @@ where
RevalidationType::Light =>
(revalidation::RevalidationQueue::new(pool_api.clone(), pool.clone()), None),
RevalidationType::Full => {
let (queue, background) =
revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone());
let (queue, background) = revalidation::RevalidationQueue::new_background(
pool_api.clone(),
pool.clone(),
finalized_hash,
);
(queue, Some(background))
},
};
@@ -254,46 +260,43 @@ where
fn submit_at(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xts: Vec<TransactionFor<Self>>,
) -> PoolFuture<Vec<Result<TxHash<Self>, Self::Error>>, Self::Error> {
let pool = self.pool.clone();
let at = *at;
self.metrics
.report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64));
async move { pool.submit_at(&at, source, xts).await }.boxed()
async move { pool.submit_at(at, source, xts).await }.boxed()
}
fn submit_one(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<TxHash<Self>, Self::Error> {
let pool = self.pool.clone();
let at = *at;
self.metrics.report(|metrics| metrics.submitted_transactions.inc());
async move { pool.submit_one(&at, source, xt).await }.boxed()
async move { pool.submit_one(at, source, xt).await }.boxed()
}
fn submit_and_watch(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
source: TransactionSource,
xt: TransactionFor<Self>,
) -> PoolFuture<Pin<Box<TransactionStatusStreamFor<Self>>>, Self::Error> {
let at = *at;
let pool = self.pool.clone();
self.metrics.report(|metrics| metrics.submitted_transactions.inc());
async move {
let watcher = pool.submit_and_watch(&at, source, xt).await?;
let watcher = pool.submit_and_watch(at, source, xt).await?;
Ok(watcher.into_stream().boxed())
}
@@ -433,11 +436,7 @@ where
let validity = self
.api
.validate_transaction_blocking(
&BlockId::hash(at),
TransactionSource::Local,
xt.clone(),
)?
.validate_transaction_blocking(at, TransactionSource::Local, xt.clone())?
.map_err(|e| {
Self::Error::Pool(match e {
TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i),
@@ -577,10 +576,7 @@ async fn prune_known_txs_for_block<Block: BlockT, Api: graph::ChainApi<Block = B
},
};
if let Err(e) = pool
.prune(&BlockId::Hash(block_hash), &BlockId::hash(*header.parent_hash()), &extrinsics)
.await
{
if let Err(e) = pool.prune(block_hash, *header.parent_hash(), &extrinsics).await {
log::error!("Cannot prune known in the pool: {}", e);
}
@@ -691,7 +687,7 @@ where
if let Err(e) = pool
.resubmit_at(
&BlockId::Hash(*hash),
*hash,
// These transactions are coming from retracted blocks, we should
// simply consider them external.
TransactionSource::External,
@@ -717,7 +713,7 @@ where
if next_action.revalidate {
let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect();
self.revalidation_queue.revalidate_later(*block_number, hashes).await;
self.revalidation_queue.revalidate_later(*hash, hashes).await;
self.revalidation_strategy.lock().clear();
}
@@ -25,14 +25,12 @@ use std::{
};
use crate::{
graph::{ChainApi, ExtrinsicHash, NumberFor, Pool, ValidatedTransaction},
graph::{BlockHash, ChainApi, ExtrinsicHash, Pool, ValidatedTransaction},
LOG_TARGET,
};
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use sp_runtime::{
generic::BlockId,
traits::{SaturatedConversion, Zero},
transaction_validity::TransactionValidityError,
generic::BlockId, traits::SaturatedConversion, transaction_validity::TransactionValidityError,
};
use futures::prelude::*;
@@ -44,7 +42,7 @@ const MIN_BACKGROUND_REVALIDATION_BATCH_SIZE: usize = 20;
/// Payload from queue to worker.
struct WorkerPayload<Api: ChainApi> {
at: NumberFor<Api>,
at: BlockHash<Api>,
transactions: Vec<ExtrinsicHash<Api>>,
}
@@ -54,9 +52,9 @@ struct WorkerPayload<Api: ChainApi> {
struct RevalidationWorker<Api: ChainApi> {
api: Arc<Api>,
pool: Arc<Pool<Api>>,
best_block: NumberFor<Api>,
block_ordered: BTreeMap<NumberFor<Api>, HashSet<ExtrinsicHash<Api>>>,
members: HashMap<ExtrinsicHash<Api>, NumberFor<Api>>,
best_block: BlockHash<Api>,
block_ordered: BTreeMap<BlockHash<Api>, HashSet<ExtrinsicHash<Api>>>,
members: HashMap<ExtrinsicHash<Api>, BlockHash<Api>>,
}
impl<Api: ChainApi> Unpin for RevalidationWorker<Api> {}
@@ -68,15 +66,30 @@ impl<Api: ChainApi> Unpin for RevalidationWorker<Api> {}
async fn batch_revalidate<Api: ChainApi>(
pool: Arc<Pool<Api>>,
api: Arc<Api>,
at: NumberFor<Api>,
at: BlockHash<Api>,
batch: impl IntoIterator<Item = ExtrinsicHash<Api>>,
) {
// This conversion should work. Otherwise, for unknown block the revalidation shall be skipped,
// all the transactions will be kept in the validated pool, and can be scheduled for
// revalidation with the next request.
let block_number = match api.block_id_to_number(&BlockId::Hash(at)) {
Ok(Some(n)) => n,
Ok(None) => {
log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}, could not get block number.");
return
},
Err(e) => {
log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}: {e:?}.");
return
},
};
let mut invalid_hashes = Vec::new();
let mut revalidated = HashMap::new();
let validation_results = futures::future::join_all(batch.into_iter().filter_map(|ext_hash| {
pool.validated_pool().ready_by_hash(&ext_hash).map(|ext| {
api.validate_transaction(&BlockId::Number(at), ext.source, ext.data.clone())
api.validate_transaction(at, ext.source, ext.data.clone())
.map(move |validation_result| (validation_result, ext_hash, ext))
})
}))
@@ -107,7 +120,7 @@ async fn batch_revalidate<Api: ChainApi>(
revalidated.insert(
ext_hash,
ValidatedTransaction::valid_at(
at.saturated_into::<u64>(),
block_number.saturated_into::<u64>(),
ext_hash,
ext.source,
ext.data.clone(),
@@ -135,13 +148,13 @@ async fn batch_revalidate<Api: ChainApi>(
}
impl<Api: ChainApi> RevalidationWorker<Api> {
fn new(api: Arc<Api>, pool: Arc<Pool<Api>>) -> Self {
fn new(api: Arc<Api>, pool: Arc<Pool<Api>>, best_block: BlockHash<Api>) -> Self {
Self {
api,
pool,
best_block,
block_ordered: Default::default(),
members: Default::default(),
best_block: Zero::zero(),
}
}
@@ -303,10 +316,11 @@ where
api: Arc<Api>,
pool: Arc<Pool<Api>>,
interval: Duration,
best_block: BlockHash<Api>,
) -> (Self, Pin<Box<dyn Future<Output = ()> + Send>>) {
let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue", 100_000);
let worker = RevalidationWorker::new(api.clone(), pool.clone());
let worker = RevalidationWorker::new(api.clone(), pool.clone(), best_block);
let queue = Self { api, pool, background: Some(to_worker) };
@@ -317,8 +331,9 @@ where
pub fn new_background(
api: Arc<Api>,
pool: Arc<Pool<Api>>,
best_block: BlockHash<Api>,
) -> (Self, Pin<Box<dyn Future<Output = ()> + Send>>) {
Self::new_with_interval(api, pool, BACKGROUND_REVALIDATION_INTERVAL)
Self::new_with_interval(api, pool, BACKGROUND_REVALIDATION_INTERVAL, best_block)
}
/// Queue some transaction for later revalidation.
@@ -328,7 +343,7 @@ where
/// revalidation is actually done.
pub async fn revalidate_later(
&self,
at: NumberFor<Api>,
at: BlockHash<Api>,
transactions: Vec<ExtrinsicHash<Api>>,
) {
if transactions.len() > 0 {
@@ -360,9 +375,8 @@ mod tests {
};
use futures::executor::block_on;
use sc_transaction_pool_api::TransactionSource;
use sp_runtime::generic::BlockId;
use substrate_test_runtime::{AccountId, Transfer, H256};
use substrate_test_runtime_client::AccountKeyring::Alice;
use substrate_test_runtime_client::AccountKeyring::{Alice, Bob};
#[test]
fn revalidation_queue_works() {
@@ -376,18 +390,63 @@ mod tests {
amount: 5,
nonce: 0,
});
let uxt_hash = block_on(pool.submit_one(
&BlockId::number(0),
TransactionSource::External,
uxt.clone(),
))
.expect("Should be valid");
block_on(queue.revalidate_later(0, vec![uxt_hash]));
let hash_of_block0 = api.expect_hash_from_number(0);
let uxt_hash =
block_on(pool.submit_one(hash_of_block0, TransactionSource::External, uxt.clone()))
.expect("Should be valid");
block_on(queue.revalidate_later(hash_of_block0, vec![uxt_hash]));
// revalidated in sync offload 2nd time
assert_eq!(api.validation_requests().len(), 2);
// number of ready
assert_eq!(pool.validated_pool().status().ready, 1);
}
#[test]
fn revalidation_queue_skips_revalidation_for_unknown_block_hash() {
let api = Arc::new(TestApi::default());
let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone()));
let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone()));
let uxt0 = uxt(Transfer {
from: Alice.into(),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 5,
nonce: 0,
});
let uxt1 = uxt(Transfer {
from: Bob.into(),
to: AccountId::from_h256(H256::from_low_u64_be(2)),
amount: 4,
nonce: 1,
});
let hash_of_block0 = api.expect_hash_from_number(0);
let unknown_block = H256::repeat_byte(0x13);
let uxt_hashes =
block_on(pool.submit_at(hash_of_block0, TransactionSource::External, vec![uxt0, uxt1]))
.expect("Should be valid")
.into_iter()
.map(|r| r.expect("Should be valid"))
.collect::<Vec<_>>();
assert_eq!(api.validation_requests().len(), 2);
assert_eq!(pool.validated_pool().status().ready, 2);
// revalidation works fine for block 0:
block_on(queue.revalidate_later(hash_of_block0, uxt_hashes.clone()));
assert_eq!(api.validation_requests().len(), 4);
assert_eq!(pool.validated_pool().status().ready, 2);
// revalidation shall be skipped for unknown block:
block_on(queue.revalidate_later(unknown_block, uxt_hashes));
// no revalidation shall be done
assert_eq!(api.validation_requests().len(), 4);
// number of ready shall not change
assert_eq!(pool.validated_pool().status().ready, 2);
}
}
+14 -6
View File
@@ -32,7 +32,7 @@ use sp_runtime::{
};
use std::{collections::HashSet, sync::Arc};
use substrate_test_runtime::{
substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, Extrinsic,
substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, BlockNumber, Extrinsic,
ExtrinsicBuilder, Hashing, RuntimeCall, Transfer, TransferData, H256,
};
@@ -53,6 +53,11 @@ impl TestApi {
pub fn validation_requests(&self) -> Vec<Extrinsic> {
self.validation_requests.lock().clone()
}
/// Helper function for mapping block number to hash. Use if mapping shall not fail.
pub fn expect_hash_from_number(&self, n: BlockNumber) -> H256 {
self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap()
}
}
impl ChainApi for TestApi {
@@ -64,13 +69,13 @@ impl ChainApi for TestApi {
/// Verify extrinsic at given block.
fn validate_transaction(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
_source: TransactionSource,
uxt: ExtrinsicFor<Self>,
) -> Self::ValidationFuture {
self.validation_requests.lock().push(uxt.clone());
let hash = self.hash_and_length(&uxt).0;
let block_number = self.block_id_to_number(at).unwrap().unwrap();
let block_number = self.block_id_to_number(&BlockId::Hash(at)).unwrap().unwrap();
let res = match uxt {
Extrinsic {
@@ -153,6 +158,8 @@ impl ChainApi for TestApi {
) -> Result<Option<NumberFor<Self>>, Self::Error> {
Ok(match at {
BlockId::Number(num) => Some(*num),
BlockId::Hash(hash) if *hash == H256::from_low_u64_be(hash.to_low_u64_be()) =>
Some(hash.to_low_u64_be()),
BlockId::Hash(_) => None,
})
}
@@ -164,7 +171,7 @@ impl ChainApi for TestApi {
) -> Result<Option<<Self::Block as BlockT>::Hash>, Self::Error> {
Ok(match at {
BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(),
BlockId::Hash(_) => None,
BlockId::Hash(hash) => Some(*hash),
})
}
@@ -199,6 +206,7 @@ pub(crate) fn uxt(transfer: Transfer) -> Extrinsic {
ExtrinsicBuilder::new_transfer(transfer).build()
}
pub(crate) fn pool() -> Pool<TestApi> {
Pool::new(Default::default(), true.into(), TestApi::default().into())
pub(crate) fn pool() -> (Pool<TestApi>, Arc<TestApi>) {
let api = Arc::new(TestApi::default());
(Pool::new(Default::default(), true.into(), api.clone()), api)
}
+282 -198
View File
@@ -47,8 +47,9 @@ use substrate_test_runtime_transaction_pool::{uxt, TestApi};
const LOG_TARGET: &str = "txpool";
fn pool() -> Pool<TestApi> {
Pool::new(Default::default(), true.into(), TestApi::with_alice_nonce(209).into())
fn pool() -> (Pool<TestApi>, Arc<TestApi>) {
let api = Arc::new(TestApi::with_alice_nonce(209));
(Pool::new(Default::default(), true.into(), api.clone()), api)
}
fn maintained_pool() -> (BasicPool<TestApi, Block>, Arc<TestApi>, futures::executor::ThreadPool) {
@@ -83,8 +84,8 @@ const SOURCE: TransactionSource = TransactionSource::External;
#[test]
fn submission_should_work() {
let pool = pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
let (pool, api) = pool();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
@@ -96,9 +97,9 @@ fn submission_should_work() {
#[test]
fn multiple_submission_should_work() {
let pool = pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
let (pool, api) = pool();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
@@ -111,8 +112,8 @@ fn multiple_submission_should_work() {
#[test]
fn early_nonce_should_be_culled() {
sp_tracing::try_init_simple();
let pool = pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 208))).unwrap();
let (pool, api) = pool();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 208))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
@@ -124,9 +125,9 @@ fn early_nonce_should_be_culled() {
#[test]
fn late_nonce_should_be_queued() {
let pool = pool();
let (pool, api) = pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
.ready()
@@ -134,7 +135,7 @@ fn late_nonce_should_be_queued() {
.collect();
assert_eq!(pending, Vec::<Nonce>::new());
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
.ready()
@@ -145,9 +146,10 @@ fn late_nonce_should_be_queued() {
#[test]
fn prune_tags_should_work() {
let pool = pool();
let hash209 = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
let (pool, api) = pool();
let hash209 =
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap();
let pending: Vec<_> = pool
.validated_pool()
@@ -157,7 +159,7 @@ fn prune_tags_should_work() {
assert_eq!(pending, vec![209, 210]);
pool.validated_pool().api().push_block(1, Vec::new(), true);
block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![hash209]))
block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![hash209]))
.expect("Prune tags");
let pending: Vec<_> = pool
@@ -170,11 +172,12 @@ fn prune_tags_should_work() {
#[test]
fn should_ban_invalid_transactions() {
let pool = pool();
let (pool, api) = pool();
let uxt = uxt(Alice, 209);
let hash = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap();
let hash =
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap();
pool.validated_pool().remove_invalid(&[hash]);
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err();
// when
let pending: Vec<_> = pool
@@ -185,7 +188,7 @@ fn should_ban_invalid_transactions() {
assert_eq!(pending, Vec::<Nonce>::new());
// then
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err();
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err();
}
#[test]
@@ -193,9 +196,9 @@ fn only_prune_on_new_best() {
let (pool, api, _) = maintained_pool();
let uxt = uxt(Alice, 209);
let _ = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, uxt.clone()))
let _ = block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt.clone()))
.expect("1. Imported");
pool.api().push_block(1, vec![uxt.clone()], true);
api.push_block(1, vec![uxt.clone()], true);
assert_eq!(pool.status().ready, 1);
let header = api.push_block(2, vec![uxt], true);
@@ -212,13 +215,15 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
}));
let pool = Pool::new(Default::default(), true.into(), api.clone());
let xt = uxt(Alice, 209);
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.validated_pool().status().ready, 1);
// remove the transaction that just got imported.
api.increment_nonce(Alice.into());
api.push_block(1, Vec::new(), true);
block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![])).expect("1. Pruned");
block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![]))
.expect("1. Pruned");
assert_eq!(pool.validated_pool().status().ready, 0);
// it's re-imported to future
assert_eq!(pool.validated_pool().status().future, 1);
@@ -227,7 +232,8 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
api.increment_nonce(Alice.into());
api.push_block(2, Vec::new(), true);
let xt = uxt(Alice, 211);
block_on(pool.submit_one(&BlockId::number(2), SOURCE, xt.clone())).expect("2. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(2), SOURCE, xt.clone()))
.expect("2. Imported");
assert_eq!(pool.validated_pool().status().ready, 1);
assert_eq!(pool.validated_pool().status().future, 1);
let pending: Vec<_> = pool
@@ -240,7 +246,8 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
// prune it and make sure the pool is empty
api.increment_nonce(Alice.into());
api.push_block(3, Vec::new(), true);
block_on(pool.prune_tags(&BlockId::number(3), vec![vec![155]], vec![])).expect("2. Pruned");
block_on(pool.prune_tags(api.expect_hash_from_number(3), vec![vec![155]], vec![]))
.expect("2. Pruned");
assert_eq!(pool.validated_pool().status().ready, 0);
assert_eq!(pool.validated_pool().status().future, 2);
}
@@ -270,7 +277,8 @@ fn should_prune_old_during_maintenance() {
let (pool, api, _guard) = maintained_pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![xt.clone()], true);
@@ -285,9 +293,11 @@ fn should_revalidate_during_maintenance() {
let xt2 = uxt(Alice, 210);
let (pool, api, _guard) = maintained_pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt2.clone()))
.expect("2. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone()))
.expect("1. Imported");
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt2.clone()))
.expect("2. Imported");
assert_eq!(pool.status().ready, 2);
assert_eq!(api.validation_requests().len(), 2);
@@ -311,7 +321,8 @@ fn should_resubmit_from_retracted_during_maintenance() {
let (pool, api, _guard) = maintained_pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![], true);
@@ -329,7 +340,8 @@ fn should_not_resubmit_from_retracted_during_maintenance_if_tx_is_also_in_enacte
let (pool, api, _guard) = maintained_pool();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![xt.clone()], true);
@@ -347,8 +359,9 @@ fn should_not_retain_invalid_hashes_from_retracted() {
let (pool, api, _guard) = maintained_pool();
let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone()))
.expect("1. Imported");
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![], true);
@@ -374,15 +387,18 @@ fn should_revalidate_across_many_blocks() {
let (pool, api, _guard) = maintained_pool();
let watcher1 = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt1.clone()))
let watcher1 =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt1.clone()))
.expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt2.clone()))
.expect("1. Imported");
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt2.clone())).expect("1. Imported");
assert_eq!(pool.status().ready, 2);
let header = api.push_block(1, vec![], true);
block_on(pool.maintain(block_event(header)));
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt3.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt3.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 3);
let header = api.push_block(2, vec![xt1.clone()], true);
@@ -409,19 +425,24 @@ fn should_push_watchers_during_maintenance() {
let tx0 = alice_uxt(0);
let watcher0 =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx0.clone())).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx0.clone()))
.unwrap();
let tx1 = alice_uxt(1);
let watcher1 =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx1.clone())).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx1.clone()))
.unwrap();
let tx2 = alice_uxt(2);
let watcher2 =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx2.clone())).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx2.clone()))
.unwrap();
let tx3 = alice_uxt(3);
let watcher3 =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx3.clone())).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx3.clone()))
.unwrap();
let tx4 = alice_uxt(4);
let watcher4 =
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, tx4.clone())).unwrap();
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, tx4.clone()))
.unwrap();
assert_eq!(pool.status().ready, 5);
// when
@@ -489,11 +510,13 @@ fn finalization() {
let api = TestApi::with_alice_nonce(209);
api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone()))
.expect("1. Imported");
pool.api().push_block(2, vec![xt.clone()], true);
let api = pool.api();
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, xt.clone()))
.expect("1. Imported");
api.push_block(2, vec![xt.clone()], true);
let header = pool.api().chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone();
let header = api.chain().read().block_by_number.get(&2).unwrap()[0].0.header().clone();
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
block_on(pool.maintain(event));
@@ -515,16 +538,17 @@ fn fork_aware_finalization() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let mut canon_watchers = vec![];
let from_alice = uxt(Alice, 1);
let from_dave = uxt(Dave, 2);
let from_bob = uxt(Bob, 1);
let from_charlie = uxt(Charlie, 1);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Dave.into());
pool.api().increment_nonce(Charlie.into());
pool.api().increment_nonce(Bob.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Dave.into());
api.increment_nonce(Charlie.into());
api.increment_nonce(Bob.into());
let from_dave_watcher;
let from_bob_watcher;
@@ -538,10 +562,13 @@ fn fork_aware_finalization() {
// block B1
{
let watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header = pool.api().push_block(2, vec![from_alice.clone()], true);
let watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block(2, vec![from_alice.clone()], true);
canon_watchers.push((watcher, header.hash()));
assert_eq!(pool.status().ready, 1);
@@ -556,10 +583,13 @@ fn fork_aware_finalization() {
// block C2
{
let header = pool.api().push_block_with_parent(b1, vec![from_dave.clone()], true);
from_dave_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone()))
.expect("1. Imported");
let header = api.push_block_with_parent(b1, vec![from_dave.clone()], true);
from_dave_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_dave.clone(),
))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> C2: {:?} {:?}", header.hash(), header);
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
@@ -570,11 +600,14 @@ fn fork_aware_finalization() {
// block D2
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = pool.api().push_block_with_parent(c2, vec![from_bob.clone()], true);
let header = api.push_block_with_parent(c2, vec![from_bob.clone()], true);
log::trace!(target: LOG_TARGET, ">> D2: {:?} {:?}", header.hash(), header);
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
@@ -585,15 +618,18 @@ fn fork_aware_finalization() {
// block C1
{
let watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone()))
.expect("1.Imported");
let watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_charlie.clone(),
))
.expect("1.Imported");
assert_eq!(pool.status().ready, 1);
let header = pool.api().push_block_with_parent(b1, vec![from_charlie.clone()], true);
let header = api.push_block_with_parent(b1, vec![from_charlie.clone()], true);
log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header);
c1 = header.hash();
canon_watchers.push((watcher, header.hash()));
let event = block_event_with_retracted(header.clone(), d2, pool.api());
let event = block_event_with_retracted(header.clone(), d2, api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 2);
@@ -604,10 +640,10 @@ fn fork_aware_finalization() {
// block D1
{
let xt = uxt(Eve, 0);
let w = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone()))
let w = block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 3);
let header = pool.api().push_block_with_parent(c1, vec![xt.clone()], true);
let header = api.push_block_with_parent(c1, vec![xt.clone()], true);
log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header);
d1 = header.hash();
canon_watchers.push((w, header.hash()));
@@ -623,7 +659,7 @@ fn fork_aware_finalization() {
// block E1
{
let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true);
let header = api.push_block_with_parent(d1, vec![from_dave, from_bob], true);
log::trace!(target: LOG_TARGET, ">> E1: {:?} {:?}", header.hash(), header);
e1 = header.hash();
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
@@ -673,16 +709,18 @@ fn prune_and_retract_tx_at_same_time() {
api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
pool.api().increment_nonce(Alice.into());
api.increment_nonce(Alice.into());
let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
// Block B1
let b1 = {
let header = pool.api().push_block(2, vec![from_alice.clone()], true);
let header = api.push_block(2, vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
@@ -693,10 +731,10 @@ fn prune_and_retract_tx_at_same_time() {
// Block B2
let b2 = {
let header = pool.api().push_block(2, vec![from_alice.clone()], true);
let header = api.push_block(2, vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 0);
let event = block_event_with_retracted(header.clone(), b1, pool.api());
let event = block_event_with_retracted(header.clone(), b1, api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 0);
@@ -739,19 +777,21 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() {
api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let tx0 = uxt(Alice, 1);
let tx1 = uxt(Dave, 2);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Dave.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Dave.into());
let d0;
// Block D0
{
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone()))
.expect("1. Imported");
let header = pool.api().push_block(2, vec![tx0.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx0.clone()))
.expect("1. Imported");
let header = api.push_block(2, vec![tx0.clone()], true);
assert_eq!(pool.status().ready, 1);
let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None };
@@ -762,17 +802,18 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() {
// Block D1
{
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone()))
.expect("1. Imported");
pool.api().push_block(2, vec![tx1.clone()], false);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx1.clone()))
.expect("1. Imported");
api.push_block(2, vec![tx1.clone()], false);
assert_eq!(pool.status().ready, 1);
}
// Block D2
{
//push new best block
let header = pool.api().push_block(2, vec![], true);
let event = block_event_with_retracted(header, d0, pool.api());
let header = api.push_block(2, vec![], true);
let event = block_event_with_retracted(header, d0, api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 2);
}
@@ -786,6 +827,8 @@ fn resubmit_from_retracted_fork() {
let pool = create_basic_pool(api);
let api = pool.api();
let tx0 = uxt(Alice, 1);
let tx1 = uxt(Dave, 2);
let tx2 = uxt(Bob, 3);
@@ -795,18 +838,19 @@ fn resubmit_from_retracted_fork() {
let tx4 = uxt(Ferdie, 2);
let tx5 = uxt(One, 3);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Dave.into());
pool.api().increment_nonce(Bob.into());
pool.api().increment_nonce(Eve.into());
pool.api().increment_nonce(Ferdie.into());
pool.api().increment_nonce(One.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Dave.into());
api.increment_nonce(Bob.into());
api.increment_nonce(Eve.into());
api.increment_nonce(Ferdie.into());
api.increment_nonce(One.into());
// Block D0
{
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx0.clone()))
.expect("1. Imported");
let header = pool.api().push_block(2, vec![tx0.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx0.clone()))
.expect("1. Imported");
let header = api.push_block(2, vec![tx0.clone()], true);
assert_eq!(pool.status().ready, 1);
block_on(pool.maintain(block_event(header)));
@@ -815,18 +859,20 @@ fn resubmit_from_retracted_fork() {
// Block E0
{
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx1.clone()))
.expect("1. Imported");
let header = pool.api().push_block(3, vec![tx1.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx1.clone()))
.expect("1. Imported");
let header = api.push_block(3, vec![tx1.clone()], true);
block_on(pool.maintain(block_event(header)));
assert_eq!(pool.status().ready, 0);
}
// Block F0
let f0 = {
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx2.clone()))
.expect("1. Imported");
let header = pool.api().push_block(4, vec![tx2.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx2.clone()))
.expect("1. Imported");
let header = api.push_block(4, vec![tx2.clone()], true);
block_on(pool.maintain(block_event(header.clone())));
assert_eq!(pool.status().ready, 0);
header.hash()
@@ -834,27 +880,30 @@ fn resubmit_from_retracted_fork() {
// Block D1
let d1 = {
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx3.clone()))
.expect("1. Imported");
let header = pool.api().push_block(2, vec![tx3.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx3.clone()))
.expect("1. Imported");
let header = api.push_block(2, vec![tx3.clone()], true);
assert_eq!(pool.status().ready, 1);
header.hash()
};
// Block E1
let e1 = {
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx4.clone()))
.expect("1. Imported");
let header = pool.api().push_block_with_parent(d1, vec![tx4.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx4.clone()))
.expect("1. Imported");
let header = api.push_block_with_parent(d1, vec![tx4.clone()], true);
assert_eq!(pool.status().ready, 2);
header.hash()
};
// Block F1
let f1_header = {
let _ = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, tx5.clone()))
.expect("1. Imported");
let header = pool.api().push_block_with_parent(e1, vec![tx5.clone()], true);
let _ =
block_on(pool.submit_and_watch(api.expect_hash_from_number(1), SOURCE, tx5.clone()))
.expect("1. Imported");
let header = api.push_block_with_parent(e1, vec![tx5.clone()], true);
// Don't announce the block event to the pool directly, because we will
// re-org to this block.
assert_eq!(pool.status().ready, 3);
@@ -865,7 +914,7 @@ fn resubmit_from_retracted_fork() {
let expected_ready = vec![tx3, tx4, tx5].iter().map(Encode::encode).collect::<BTreeSet<_>>();
assert_eq!(expected_ready, ready);
let event = block_event_with_retracted(f1_header, f0, pool.api());
let event = block_event_with_retracted(f1_header, f0, api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 3);
@@ -876,9 +925,10 @@ fn resubmit_from_retracted_fork() {
#[test]
fn ready_set_should_not_resolve_before_block_update() {
let (pool, _api, _guard) = maintained_pool();
let (pool, api, _guard) = maintained_pool();
let xt1 = uxt(Alice, 209);
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone()))
.expect("1. Imported");
assert!(pool.ready_at(1).now_or_never().is_none());
}
@@ -890,7 +940,8 @@ fn ready_set_should_resolve_after_block_update() {
let xt1 = uxt(Alice, 209);
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt1.clone()))
.expect("1. Imported");
block_on(pool.maintain(block_event(header)));
assert!(pool.ready_at(1).now_or_never().is_some());
@@ -903,7 +954,8 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() {
let xt1 = uxt(Alice, 209);
block_on(pool.submit_one(&BlockId::number(1), SOURCE, xt1.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt1.clone()))
.expect("1. Imported");
let noop_waker = futures::task::noop_waker();
let mut context = futures::task::Context::from_waker(&noop_waker);
@@ -948,7 +1000,12 @@ fn import_notification_to_pool_maintain_works() {
// Prepare the extrisic, push it to the pool and check that it was added.
let xt = uxt(Alice, 0);
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())).expect("1. Imported");
block_on(pool.submit_one(
pool.api().block_id_to_hash(&BlockId::Number(0)).unwrap().unwrap(),
SOURCE,
xt.clone(),
))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let mut import_stream = block_on_stream(client.import_notification_stream());
@@ -973,7 +1030,8 @@ fn pruning_a_transaction_should_remove_it_from_best_transaction() {
let xt1 = ExtrinsicBuilder::new_include_data(Vec::new()).build();
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![xt1.clone()], true);
@@ -997,8 +1055,12 @@ fn stale_transactions_are_pruned() {
let (pool, api, _guard) = maintained_pool();
xts.into_iter().for_each(|xt| {
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.into_unchecked_extrinsic()))
.expect("1. Imported");
block_on(pool.submit_one(
api.expect_hash_from_number(0),
SOURCE,
xt.into_unchecked_extrinsic(),
))
.expect("1. Imported");
});
assert_eq!(pool.status().ready, 0);
assert_eq!(pool.status().future, 3);
@@ -1038,8 +1100,9 @@ fn finalized_only_handled_correctly() {
let (pool, api, _guard) = maintained_pool();
let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone()))
.expect("1. Imported");
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![xt], true);
@@ -1066,8 +1129,9 @@ fn best_block_after_finalized_handled_correctly() {
let (pool, api, _guard) = maintained_pool();
let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone()))
.expect("1. Imported");
let watcher =
block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt.clone()))
.expect("1. Imported");
assert_eq!(pool.status().ready, 1);
let header = api.push_block(1, vec![xt], true);
@@ -1096,11 +1160,12 @@ fn switching_fork_with_finalized_works() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
let from_bob = uxt(Bob, 2);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Bob.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Bob.into());
let from_alice_watcher;
let from_bob_watcher;
@@ -1109,12 +1174,13 @@ fn switching_fork_with_finalized_works() {
// block B1
{
from_alice_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
from_alice_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header);
b1_header = header;
@@ -1122,10 +1188,13 @@ fn switching_fork_with_finalized_works() {
// block B2
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
let header = pool.api().push_block_with_parent(
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(
a_header.hash(),
vec![from_alice.clone(), from_bob.clone()],
true,
@@ -1174,11 +1243,12 @@ fn switching_fork_multiple_times_works() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
let from_bob = uxt(Bob, 2);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Bob.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Bob.into());
let from_alice_watcher;
let from_bob_watcher;
@@ -1187,12 +1257,13 @@ fn switching_fork_multiple_times_works() {
// block B1
{
from_alice_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
from_alice_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header);
b1_header = header;
@@ -1200,10 +1271,13 @@ fn switching_fork_multiple_times_works() {
// block B2
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
let header = pool.api().push_block_with_parent(
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(
a_header.hash(),
vec![from_alice.clone(), from_bob.clone()],
true,
@@ -1223,14 +1297,14 @@ fn switching_fork_multiple_times_works() {
{
// phase-1
let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), pool.api());
let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 0);
}
{
// phase-2
let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), pool.api());
let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), api);
block_on(pool.maintain(event));
assert_eq!(pool.status().ready, 1);
}
@@ -1282,13 +1356,14 @@ fn two_blocks_delayed_finalization_works() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
let from_bob = uxt(Bob, 2);
let from_charlie = uxt(Charlie, 3);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Bob.into());
pool.api().increment_nonce(Charlie.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Bob.into());
api.increment_nonce(Charlie.into());
let from_alice_watcher;
let from_bob_watcher;
@@ -1299,12 +1374,13 @@ fn two_blocks_delayed_finalization_works() {
// block B1
{
from_alice_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
from_alice_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header);
@@ -1313,12 +1389,13 @@ fn two_blocks_delayed_finalization_works() {
// block C1
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
assert_eq!(pool.status().ready, 2);
log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header);
@@ -1327,12 +1404,13 @@ fn two_blocks_delayed_finalization_works() {
// block D1
{
from_charlie_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true);
from_charlie_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_charlie.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true);
assert_eq!(pool.status().ready, 3);
log::trace!(target: LOG_TARGET, ">> D1: {:?} {:?}", header.hash(), header);
@@ -1398,11 +1476,12 @@ fn delayed_finalization_does_not_retract() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
let from_bob = uxt(Bob, 2);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Bob.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Bob.into());
let from_alice_watcher;
let from_bob_watcher;
@@ -1411,12 +1490,13 @@ fn delayed_finalization_does_not_retract() {
// block B1
{
from_alice_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
from_alice_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header);
@@ -1425,12 +1505,13 @@ fn delayed_finalization_does_not_retract() {
// block C1
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
assert_eq!(pool.status().ready, 2);
log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header);
@@ -1493,11 +1574,12 @@ fn best_block_after_finalization_does_not_retract() {
let a_header = api.push_block(1, vec![], true);
let pool = create_basic_pool(api);
let api = pool.api();
let from_alice = uxt(Alice, 1);
let from_bob = uxt(Bob, 2);
pool.api().increment_nonce(Alice.into());
pool.api().increment_nonce(Bob.into());
api.increment_nonce(Alice.into());
api.increment_nonce(Bob.into());
let from_alice_watcher;
let from_bob_watcher;
@@ -1506,12 +1588,13 @@ fn best_block_after_finalization_does_not_retract() {
// block B1
{
from_alice_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
from_alice_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_alice.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true);
assert_eq!(pool.status().ready, 1);
log::trace!(target: LOG_TARGET, ">> B1: {:?} {:?}", header.hash(), header);
@@ -1520,12 +1603,13 @@ fn best_block_after_finalization_does_not_retract() {
// block C1
{
from_bob_watcher =
block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone()))
.expect("1. Imported");
let header =
pool.api()
.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
from_bob_watcher = block_on(pool.submit_and_watch(
api.expect_hash_from_number(1),
SOURCE,
from_bob.clone(),
))
.expect("1. Imported");
let header = api.push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true);
assert_eq!(pool.status().ready, 2);
log::trace!(target: LOG_TARGET, ">> C1: {:?} {:?}", header.hash(), header);
@@ -22,6 +22,7 @@
use codec::Encode;
use futures::future::ready;
use parking_lot::RwLock;
use sc_transaction_pool::ChainApi;
use sp_blockchain::{CachedHeaderMetadata, TreeRoute};
use sp_runtime::{
generic::{self, BlockId},
@@ -237,9 +238,14 @@ impl TestApi {
) -> Result<sp_blockchain::TreeRoute<Block>, Error> {
sp_blockchain::tree_route(self, from, to)
}
/// Helper function for mapping block number to hash. Use if mapping shall not fail.
pub fn expect_hash_from_number(&self, n: BlockNumber) -> Hash {
self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap()
}
}
impl sc_transaction_pool::ChainApi for TestApi {
impl ChainApi for TestApi {
type Block = Block;
type Error = Error;
type ValidationFuture = futures::future::Ready<Result<TransactionValidity, Error>>;
@@ -247,13 +253,13 @@ impl sc_transaction_pool::ChainApi for TestApi {
fn validate_transaction(
&self,
at: &BlockId<Self::Block>,
at: <Self::Block as BlockT>::Hash,
_source: TransactionSource,
uxt: <Self::Block as BlockT>::Extrinsic,
) -> Self::ValidationFuture {
self.validation_requests.write().push(uxt.clone());
match self.block_id_to_number(at) {
match self.block_id_to_number(&BlockId::Hash(at)) {
Ok(Some(number)) => {
let found_best = self
.chain
+3 -3
View File
@@ -219,7 +219,6 @@ mod tests {
use jsonrpsee::{core::Error as JsonRpseeError, types::error::CallError};
use sc_transaction_pool::BasicPool;
use sp_runtime::{
generic::BlockId,
transaction_validity::{InvalidTransaction, TransactionValidityError},
ApplyExtrinsicResult,
};
@@ -245,11 +244,12 @@ mod tests {
};
t.into_unchecked_extrinsic()
};
let hash_of_block0 = client.info().genesis_hash;
// Populate the pool
let ext0 = new_transaction(0);
block_on(pool.submit_one(&BlockId::number(0), source, ext0)).unwrap();
block_on(pool.submit_one(hash_of_block0, source, ext0)).unwrap();
let ext1 = new_transaction(1);
block_on(pool.submit_one(&BlockId::number(0), source, ext1)).unwrap();
block_on(pool.submit_one(hash_of_block0, source, ext1)).unwrap();
let accounts = System::new(client, pool, DenyUnsafe::Yes);