diff --git a/substrate/core/consensus/common/src/import_queue/basic_queue.rs b/substrate/core/consensus/common/src/import_queue/basic_queue.rs
index 082006ae5d..d94c3a383c 100644
--- a/substrate/core/consensus/common/src/import_queue/basic_queue.rs
+++ b/substrate/core/consensus/common/src/import_queue/basic_queue.rs
@@ -14,12 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
-use std::{pin::Pin, sync::Arc};
+use std::{mem, pin::Pin, sync::Arc, time::Duration};
use futures::{prelude::*, channel::mpsc, task::SpawnExt as _, task::Context, task::Poll};
+use futures_timer::Delay;
use runtime_primitives::{Justification, traits::{Block as BlockT, Header as HeaderT, NumberFor}};
-use crate::error::Error as ConsensusError;
-use crate::block_import::{BlockImport, BlockOrigin};
+use crate::block_import::BlockOrigin;
use crate::import_queue::{
BlockImportResult, BlockImportError, Verifier, BoxBlockImport, BoxFinalityProofImport,
BoxJustificationImport, ImportQueue, Link, Origin,
@@ -136,10 +136,10 @@ enum ToWorkerMsg {
struct BlockImportWorker> {
result_sender: BufferedLinkSender,
- block_import: BoxBlockImport,
justification_import: Option>,
finality_proof_import: Option>,
verifier: Arc,
+ delay_between_blocks: Duration,
}
impl> BlockImportWorker {
@@ -156,24 +156,55 @@ impl> BlockImportWorker {
result_sender,
verifier,
justification_import,
- block_import,
finality_proof_import,
+ delay_between_blocks: Duration::new(0, 0),
};
+ // Let's initialize `justification_import` and `finality_proof_import`.
if let Some(justification_import) = worker.justification_import.as_mut() {
for (hash, number) in justification_import.on_start() {
worker.result_sender.request_justification(&hash, number);
}
}
-
if let Some(finality_proof_import) = worker.finality_proof_import.as_mut() {
for (hash, number) in finality_proof_import.on_start() {
worker.result_sender.request_finality_proof(&hash, number);
}
}
+ // The future below has two possible states:
+ //
+ // - Currently importing many blocks, in which case `importing` is `Some` and contains a
+ // `Future`, and `block_import` is `None`.
+ // - Something else, in which case `block_import` is `Some` and `importing` is None.
+ //
+ let mut block_import = Some(block_import);
+ let mut importing = None;
+
let future = futures::future::poll_fn(move |cx| {
loop {
+ // If the results sender is closed, that means that the import queue is shutting
+ // down and we should end this future.
+ if worker.result_sender.is_closed() {
+ return Poll::Ready(())
+ }
+
+ // If we are in the process of importing a bunch of block, let's resume this
+ // process before doing anything more.
+ if let Some(imp_fut) = importing.as_mut() {
+ match Future::poll(Pin::new(imp_fut), cx) {
+ Poll::Pending => return Poll::Pending,
+ Poll::Ready(bi) => {
+ block_import = Some(bi);
+ importing = None;
+ },
+ }
+ }
+
+ debug_assert!(importing.is_none());
+ debug_assert!(block_import.is_some());
+
+ // Grab the next action request sent to the import queue.
let msg = match Stream::poll_next(Pin::new(&mut port), cx) {
Poll::Ready(Some(msg)) => msg,
Poll::Ready(None) => return Poll::Ready(()),
@@ -182,7 +213,10 @@ impl> BlockImportWorker {
match msg {
ToWorkerMsg::ImportBlocks(origin, blocks) => {
- worker.import_a_batch_of_blocks(origin, blocks);
+ // On blocks import request, we merely *start* the process and store
+ // a `Future` into `importing`.
+ let bi = block_import.take().expect("block_import is always Some; qed");
+ importing = Some(worker.import_a_batch_of_blocks(bi, origin, blocks));
},
ToWorkerMsg::ImportFinalityProof(who, hash, number, proof) => {
worker.import_finality_proof(who, hash, number, proof);
@@ -197,17 +231,24 @@ impl> BlockImportWorker {
(future, sender)
}
- fn import_a_batch_of_blocks(&mut self, origin: BlockOrigin, blocks: Vec>) {
- let result_sender = &self.result_sender;
- let (imported, count, results) = import_many_blocks(
- &mut *self.block_import,
- origin,
- blocks,
- self.verifier.clone(),
- || !result_sender.is_closed(),
- );
+ /// Returns a `Future` that imports the given blocks and sends the results on
+ /// `self.result_sender`.
+ ///
+ /// For lifetime reasons, the `BlockImport` implementation must be passed by value, and is
+ /// yielded back in the output once the import is finished.
+ fn import_a_batch_of_blocks(
+ &mut self,
+ block_import: BoxBlockImport,
+ origin: BlockOrigin,
+ blocks: Vec>
+ ) -> impl Future