Revalidate some transactions on every block import. (#4292)

* Revalidate some transactions on every block import.

* Fix endless loop in revalidate_ready.

* Clean up logging a bit.

* More clean ups.

* Print status after resubmitting.

* Remove env_logger.

* Remove redundant log.
This commit is contained in:
Tomasz Drwięga
2019-12-04 19:16:00 +01:00
committed by Gavin Wood
parent 925b23a3cd
commit 1628ba3388
6 changed files with 85 additions and 35 deletions
@@ -175,13 +175,39 @@ impl<B: ChainApi> Pool<B> {
///
/// Returns future that performs validation of all ready transactions and
/// then resubmits all transactions back to the pool.
pub fn revalidate_ready(&self, at: &BlockId<B::Block>) -> impl Future<Output=Result<(), B::Error>> {
pub fn revalidate_ready(
&self,
at: &BlockId<B::Block>,
max: Option<usize>,
) -> impl Future<Output=Result<(), B::Error>> {
use std::time::Instant;
log::debug!(target: "txpool",
"Fetching ready transactions (up to: {})",
max.map(|x| format!("{}", x)).unwrap_or_else(|| "all".into())
);
let validated_pool = self.validated_pool.clone();
let ready = self.validated_pool.ready().map(|tx| tx.data.clone());
let ready = self.validated_pool.ready()
.map(|tx| tx.data.clone())
.take(max.unwrap_or_else(usize::max_value));
let now = Instant::now();
self.verify(at, ready, false)
.map(move |revalidated_transactions| revalidated_transactions.map(
move |revalidated_transactions| validated_pool.resubmit(revalidated_transactions)
))
.map(move |revalidated_transactions| {
log::debug!(target: "txpool",
"Re-verified transactions, took {} ms. Resubmitting.",
now.elapsed().as_millis()
);
let now = Instant::now();
let res = revalidated_transactions.map(
|revalidated_transactions| validated_pool.resubmit(revalidated_transactions)
);
log::debug!(target: "txpool",
"Resubmitted. Took {} ms. Status: {:?}",
now.elapsed().as_millis(),
validated_pool.status()
);
res
})
}
/// Prunes known ready transactions.
@@ -927,7 +953,6 @@ mod tests {
#[test]
fn should_handle_pruning_in_the_middle_of_import() {
let _ = env_logger::try_init();
// given
let (ready, is_ready) = std::sync::mpsc::sync_channel(0);
let (tx, rx) = std::sync::mpsc::sync_channel(1);
@@ -1014,7 +1039,7 @@ mod tests {
pool.validated_pool.api().invalidate.lock().insert(hash3);
pool.validated_pool.api().clear_requirements.lock().insert(hash1);
pool.validated_pool.api().add_requirements.lock().insert(hash0);
block_on(pool.revalidate_ready(&BlockId::Number(0))).unwrap();
block_on(pool.revalidate_ready(&BlockId::Number(0), None)).unwrap();
// then
// hash0 now has unsatisfied requirements => it is moved to the future queue
@@ -22,7 +22,7 @@ use std::{
};
use serde::Serialize;
use log::debug;
use log::trace;
use parking_lot::RwLock;
use sp_runtime::traits::Member;
use sp_runtime::transaction_validity::{
@@ -267,7 +267,7 @@ impl<Hash: hash::Hash + Member + Serialize, Ex> ReadyTransactions<Hash, Ex> {
to_remove.append(&mut tx.unlocks);
// add to removed
debug!(target: "txpool", "[{:?}] Removed as invalid: ", hash);
trace!(target: "txpool", "[{:?}] Removed as part of the subtree.", hash);
removed.push(tx.transaction.transaction);
}
}
@@ -106,7 +106,12 @@ impl<B: ChainApi> ValidatedPool<B> {
.map(|validated_tx| self.submit_one(validated_tx))
.collect::<Vec<_>>();
let removed = self.enforce_limits();
// only enforce limits if there is at least one imported transaction
let removed = if results.iter().any(|res| res.is_ok()) {
self.enforce_limits()
} else {
Default::default()
};
results.into_iter().map(|res| match res {
Ok(ref hash) if removed.contains(hash) => Err(error::Error::ImmediatelyDropped.into()),
@@ -236,6 +241,8 @@ impl<B: ChainApi> ValidatedPool<B> {
initial_statuses.insert(removed_hash.clone(), Status::Ready);
txs_to_resubmit.push((removed_hash, tx_to_resubmit));
}
// make sure to remove the hash even if it's not present in the pool any more.
updated_transactions.remove(&hash);
}
// if we're rejecting future transactions, then insertion order matters here: