Recently, I have been trying to understand the block import for Aura and Grandpa but I don't understand some parts in substrate-node-template/node/service.rs:

1- In the new_partial() method when initializing Aura import queue, why is Aura using grandpa_block_import, isn't Aura supposed to just create blocks and should not care about justifications or finality because that's what import_block method does of GrandpaBlockImport? In the new_full() method, when starting Aura, the same thing happens, we are again using grandpa_block_import passed via block_import

2- Why would Grandpa execute blocks again or check them if we are using the same block import, shouldn't Grandpa just vote on chains using block hashes and not care what's inside the block because that's the job of Aura? because this way it should instantly finalize all aura blocks since its the same block import but is not, so what is import_block() actually doing?

having one block import is a bit annoying because imagine if you want to write your custom block import logic that does some custom verification before passing it to Aura only and not grandpa, if a majority of validators accept the block in aura, grandpa would simply finalize it by importing it directly with no verification, this would be impossible currently as they are executing the same logic.

3- I'm tempted to import the block directly via the client in the Aura import queue in new_partial(), then let grandpa do the finalization with grandpa_block_import in new_full() Meaning even if aura rejects a block it should be imported if grandpa finalized it, would that be wrong? if so, how to achieve that? because there is a note to use it carefully which I don't fully understand

NOTE: only use this implementation when there are NO consensus-level BlockImport objects. Otherwise, importing blocks directly into the client would be bypassing important verification work.

4- what does no consensus-level BlockImport objects mean?

1 Answer 1


In the new_partial() method when initializing Aura import queue it doesn't actually use grandpa's block import, it uses a grandpa's decorated block import. Block imports implement a chain of responsibility pattern (well kind of).

The very last guy is always the client. If you need to add some extra logic to that chain you create a new block import and the previous becomes nested. Now you can do additional checks, throw errors and fallback to the nested block import if needed.

So what happens in the node-template

  1. client (default block import) is created (client)
  2. grandpa wraps it with its own block import, applying his specific logic. (grandpa -> client)

That is why you have to use grandpa_block_import otherwise grandpa's logic is not executed.

Since Aura is a very simple consensus it doesn't apply any specific logic of its own. Take a look here instead. It uses both babe and grandpa. So the chain is babe -> grandpa -> client and obviously you have to use the last block_import to execute the whole chain.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.