From 71343248cafcca0b3b1dfe71ddce01aa50813acf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= <tomusdrw@users.noreply.github.com>
Date: Thu, 20 Dec 2018 15:28:14 +0100
Subject: [PATCH] Call a state before block was imported. (#1294)

* Call a state before block was imported.

* Add test to check if it works correctly.
---
 substrate/Cargo.lock                     |   1 +
 substrate/core/service/Cargo.toml        |   3 +
 substrate/core/service/src/components.rs | 126 +++++++++++++++++------
 substrate/core/service/src/lib.rs        |   3 +
 4 files changed, 103 insertions(+), 30 deletions(-)

diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 1e201f4ee53..89bfba8cb13 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -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)",
diff --git a/substrate/core/service/Cargo.toml b/substrate/core/service/Cargo.toml
index ca8766c707a..e9f165ed9d4 100644
--- a/substrate/core/service/Cargo.toml
+++ b/substrate/core/service/Cargo.toml
@@ -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" }
diff --git a/substrate/core/service/src/components.rs b/substrate/core/service/src/components.rs
index 20f01676a36..df50d54529f 100644
--- a/substrate/core/service/src/components.rs
+++ b/substrate/core/service/src/components.rs
@@ -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);
+	}
+}
diff --git a/substrate/core/service/src/lib.rs b/substrate/core/service/src/lib.rs
index 9421fcb8d01..04d8e8582ae 100644
--- a/substrate/core/service/src/lib.rs
+++ b/substrate/core/service/src/lib.rs
@@ -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;
-- 
GitLab