Call a state before block was imported. (#1294)

* Call a state before block was imported.

* Add test to check if it works correctly.
This commit is contained in:
Tomasz Drwięga
2018-12-20 15:28:14 +01:00
committed by Gav Wood
parent 23634b6b95
commit 71343248ca
4 changed files with 103 additions and 30 deletions
+1
View File
@@ -3661,6 +3661,7 @@ dependencies = [
"substrate-primitives 0.1.0",
"substrate-rpc-servers 0.1.0",
"substrate-telemetry 0.3.0",
"substrate-test-client 0.1.0",
"substrate-transaction-pool 0.1.0",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+3
View File
@@ -30,3 +30,6 @@ substrate-executor = { path = "../../core/executor" }
substrate-transaction-pool = { path = "../../core/transaction-pool" }
substrate-rpc-servers = { path = "../../core/rpc-servers" }
substrate-telemetry = { path = "../../core/telemetry" }
[dev-dependencies]
substrate-test-client = { path = "../test-client" }
+96 -30
View File
@@ -184,6 +184,51 @@ pub trait MaintainTransactionPool<C: Components> {
) -> error::Result<()>;
}
fn on_block_imported<Api, Backend, Block, Executor, PoolApi>(
id: &BlockId<Block>,
client: &Client<Backend, Executor, Block, Api>,
transaction_pool: &TransactionPool<PoolApi>,
) -> error::Result<()> where
Api: TaggedTransactionQueue<Block>,
Block: BlockT<Hash = <Blake2Hasher as ::primitives::Hasher>::Out>,
Backend: client::backend::Backend<Block, Blake2Hasher>,
Client<Backend, Executor, Block, Api>: ProvideRuntimeApi<Api = Api>,
Executor: client::CallExecutor<Block, Blake2Hasher>,
PoolApi: txpool::ChainApi<Hash = Block::Hash, Block = Block>,
{
use runtime_primitives::transaction_validity::TransactionValidity;
// Avoid calling into runtime if there is nothing to prune from the pool anyway.
if transaction_pool.status().is_empty() {
return Ok(())
}
let block = client.block(id)?;
let tags = match block {
None => return Ok(()),
Some(block) => {
let parent_id = BlockId::hash(*block.block.header().parent_hash());
let mut tags = vec![];
for tx in block.block.extrinsics() {
let tx = client.runtime_api().validate_transaction(&parent_id, &tx)?;
match tx {
TransactionValidity::Valid { mut provides, .. } => {
tags.append(&mut provides);
},
// silently ignore invalid extrinsics,
// cause they might just be inherent
_ => {}
}
}
tags
}
};
transaction_pool.prune_tags(id, tags).map_err(|e| format!("{:?}", e))?;
Ok(())
}
impl<C: Components> MaintainTransactionPool<Self> for C where
ComponentClient<C>: ProvideRuntimeApi<Api = C::RuntimeApi>,
C::RuntimeApi: TaggedTransactionQueue<ComponentBlock<C>>,
@@ -194,36 +239,7 @@ impl<C: Components> MaintainTransactionPool<Self> for C where
client: &ComponentClient<C>,
transaction_pool: &TransactionPool<C::TransactionPoolApi>,
) -> error::Result<()> {
use runtime_primitives::transaction_validity::TransactionValidity;
// Avoid calling into runtime if there is nothing to prune from the pool anyway.
if transaction_pool.status().is_empty() {
return Ok(())
}
let block = client.block(id)?;
let tags = match block {
None => return Ok(()),
Some(block) => {
let mut tags = vec![];
for tx in block.block.extrinsics() {
let tx = client.runtime_api().validate_transaction(id, &tx)?;
match tx {
TransactionValidity::Valid { mut provides, .. } => {
tags.append(&mut provides);
},
// silently ignore invalid extrinsics,
// cause they might just be inherent
_ => {}
}
}
tags
}
};
transaction_pool.prune_tags(id, tags).map_err(|e| format!("{:?}", e))?;
Ok(())
on_block_imported(id, client, transaction_pool)
}
}
@@ -520,3 +536,53 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
Factory::build_light_import_queue(config, client)
}
}
#[cfg(test)]
mod tests {
use super::*;
use codec::Encode;
use consensus_common::BlockOrigin;
use substrate_test_client::{
self,
TestClient,
keyring::Keyring,
runtime::{Extrinsic, Transfer},
};
#[test]
fn should_remove_transactions_from_the_pool() {
let client = Arc::new(substrate_test_client::new());
let pool = TransactionPool::new(Default::default(), ::transaction_pool::ChainApi::new(client.clone()));
let transaction = {
let transfer = Transfer {
amount: 5,
nonce: 0,
from: Keyring::Alice.to_raw_public().into(),
to: Default::default(),
};
let signature = Keyring::from_raw_public(transfer.from.to_fixed_bytes()).unwrap().sign(&transfer.encode()).into();
Extrinsic { transfer, signature }
};
// store the transaction in the pool
pool.submit_one(&BlockId::hash(client.best_block_header().unwrap().hash()), transaction.clone()).unwrap();
// import the block
let mut builder = client.new_block().unwrap();
builder.push(transaction.clone()).unwrap();
let block = builder.bake().unwrap();
let id = BlockId::hash(block.header().hash());
client.import(BlockOrigin::Own, block).unwrap();
// fire notification - this should clean up the queue
assert_eq!(pool.status().ready, 1);
on_block_imported(
&id,
&client,
&pool,
).unwrap();
// then
assert_eq!(pool.status().ready, 0);
assert_eq!(pool.status().future, 0);
}
}
+3
View File
@@ -50,6 +50,9 @@ extern crate log;
#[macro_use]
extern crate serde_derive;
#[cfg(test)]
extern crate substrate_test_client;
mod components;
mod error;
mod chain_spec;