Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Grandpa validator set handoff justification #1190

Merged
merged 33 commits into from
Dec 8, 2018

Conversation

andresilva
Copy link
Contributor

@andresilva andresilva commented Dec 2, 2018

Closes #1069.

finalize_block is modified to take an Option<Justification> which is stored in the database. Grandpa will store justifications for authority set change blocks, these will be available through the sync module later on and passed on to requesting nodes. Currently the sync module always requests justifications but doesn't validate whether they're provided or not, the GrandpaBlockImport will then check whether the block to be imported is a change block and whether a justification should have been provided (this is conditional on the current authority set not being live anymore).

this will allow the `BlockImport` to trigger an authority set change when
importing a change block that provides a justification (when syncing)
this will be used by `BlockImport` to check whether the authority set for a
given block is still live, if the authority set isn't live then importing a
change block requires a justification.
@andresilva andresilva added the A3-in_progress Pull request is in progress. No review needed at this stage. label Dec 2, 2018
@@ -1081,6 +1092,9 @@ impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA>
finalized,
auxiliary,
} = import_block;

assert!(justification.is_some() && finalized || justification.is_none());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should create a type: enum Finality { Finalized, FinalizedAndJustified(justification), Unfinalized }.

struct GrandpaJustification<Block: BlockT> {
round: u64,
commit: Commit<Block>,
ancestry: Vec<Block::Header>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename to vote_ancestries or something similar?

let mut ancestry_hashes = HashSet::new();
let mut ancestry = Vec::new();

let error = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we do this lazily with a closure?

@@ -644,41 +853,129 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
{
use authorities::PendingChange;

// we don't want to finalize on `inner.import_block`
let justification = block.justification.take();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this comment mean that import_block automatically finalizes when justification is Some?

The cloning and hashing within this import_block implementation could add up but perhaps this is premature optimization.

Copy link
Contributor Author

@andresilva andresilva Dec 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is the assumption. It only actually finalizes if finalized = true, but the contract of client.import_block has changed to: if a justification is provided, then the block must be finalized (this should maybe be statically typed instead of using different parameters for finalized and the justification).

}

#[derive(Clone)]
struct SharedGrandpaOracle<Block: BlockT> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a comment describing what this is for would be helpful.

as a heuristic to decide whether

  • a block has been finalized and we should expect a justification, or
  • a block hasn't been finalized and we should watch for a commit message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, added the docs to GrandpaOracle instead.

"missing justification for block that enacts authority set change".to_string()
).into());
},
_ => {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want something here for writing to the SharedAuthoritySet to note that we imported a block to the chain which should have enacted the authority set chain (this may well be a set of heads).

Actual code that periodically revisits this and re-requests justifications can be done in a follow-up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by making sure AuthoritySet only imports one pending change per fork.

debug!(target: "afg", "Restoring old set after block import error: {:?}", e);
*authorities = old_set;
}
let enacts_change = self.authority_set.inner().read().enacts_change(number, |canon_number| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably out of scope, but still: the change that is checked here (and applied later in finalize_block call) contains the same set of authorities as in the new_authorities set? Or those are/could be different sets?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also seems that if importing block with justification assumes finalization of the block (that's what @rphmeier asked above, iiuc), then imo we don't need new_authorities and authorities cache at all - we just need to refuse light-import of blocks which contain DigestItem::as_authorities_change and no justification. Could you, please, verify me here, @rphmeier ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svyatonik yep, I believe that for GRANDPA we can indeed take that kind of approach. We may still want the authorities cache for other consensus algorithms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although this is a bit of future work, because it would require tracking the authorship validator changes in GRANDPA and saving justifications for those too upon finality.

this is a little bit harder than the GRANDPA set changes because we may have a commit for block N+K where a set change happened in block N; unlike GRANDPA-set changes where honest voters can never vote beyond N. so constructing the justification may become inefficient without a good way to prove ancestry far back in the chain.

@andresilva andresilva force-pushed the andre/grandpa-handoff-justification branch from ce1c504 to e5c593c Compare December 5, 2018 18:30
@andresilva andresilva added A0-please_review Pull request needs code review. A3-in_progress Pull request is in progress. No review needed at this stage. and removed A3-in_progress Pull request is in progress. No review needed at this stage. A0-please_review Pull request needs code review. labels Dec 5, 2018
@andresilva andresilva added A0-please_review Pull request needs code review. and removed A3-in_progress Pull request is in progress. No review needed at this stage. labels Dec 7, 2018
@andresilva
Copy link
Contributor Author

I think this is good for review now, I'm still going to do some changes but I think those can be done in a follow up PR.

@rphmeier rphmeier added A8-looksgood and removed A0-please_review Pull request needs code review. labels Dec 7, 2018
@gavofyork gavofyork merged commit 8a19aa5 into master Dec 8, 2018
@gavofyork gavofyork deleted the andre/grandpa-handoff-justification branch December 8, 2018 05:35
MTDK1 pushed a commit to bdevux/substrate that referenced this pull request Apr 12, 2019
* core: make block justification optional

* runtime: update wasm binaries

* core: optionally pass justification on finalize_block

* finality-grandpa: add channel to trigger authority set changes

this will allow the `BlockImport` to trigger an authority set change when
importing a change block that provides a justification (when syncing)

* finality-grandpa: move finalize_block to free function

* finality-grandpa: add GrandpaOracle for auth set liveness checking

this will be used by `BlockImport` to check whether the authority set for a
given block is still live, if the authority set isn't live then importing a
change block requires a justification.

* finality-grandpa: store justification on finalized transition blocks

* finality-grandpa: check justification on authority set change blocks

* finality-grandpa: poll grandpa liveness oracle every 10 seconds

* finality-grandpa: spawn grandpa oracle in service setup

* core: support multiple subscriptions per consensus gossip topic

* finality-grandpa: create and verify justifications

* finality-grandpa: update to local branch of grandpa

* finality-grandpa: update to finality-grandpa v0.5.0

* finality-grandpa: move grandpa oracle code

* finality-grandpa: fix canonality check

* finality-grandpa: clean up error handling

* finality-grandpa: fix canonical_at_height

* finality-grandpa: fix tests

* runtime: update wasm binaries

* core: add tests for finalizing block with justification

* finality-grandpa: improve validation of justifications

* core: remove unused IncompleteJustification block import error

* core: test multiple subscribers for same consensus gossip topic

* Revert "finality-grandpa: improve validation of justifications"

This reverts commit 51eb2c5.

* finality-grandpa: fix commit validation

* finality-grandpa: fix commit ancestry validation

* finality-grandpa: use grandpa v0.5.1

* finality-grandpa: add docs

* finality-grandpa: fix failing test

* finality-grandpa: only allow a pending authority set change per fork

* finality-grandpa: fix validator set transition test
lamafab pushed a commit to lamafab/substrate that referenced this pull request Jun 16, 2020
* Introduce generalised proxies to polkadot

* Introduce proxy to westend

* Add proxy to Kusama.

* Fix
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants