I was exploring GRANDPA verification algorithm and stumbled upon this code by the link https://github.com/paritytech/finality-grandpa/blame/master/src/lib.rs#L494


This is the part of method validate_commit which verifies that GRANDPA finalized correctly a block given particular voter set. The usage of equivocated set is not completely clear to me. It is used only in this part of the method.

let mut equivocated = std::collections::BTreeSet::new();

// add all precommits to the round with correct counting logic
let mut round = round::Round::new(round::RoundParams {
    round_number: 0, // doesn't matter here.
    voters: voters.clone(),

for SignedPrecommit { precommit, id, signature } in &valid_precommits {
    match round.import_precommit(chain, precommit.clone(), id.clone(), signature.clone())? {
        ImportResult { equivocation: Some(_), .. } => {
            validation_result.num_equivocations += 1;
            // allow only one equivocation per voter, as extras are redundant.
            if !equivocated.insert(id) {
                return Ok(validation_result)
        ImportResult { duplicated, .. } =>
            if duplicated {
                validation_result.num_duplicated_precommits += 1;

This is how I understand this code:

  1. We detect equivocations and duplicates in round.import_precommit(...).
  2. We register the detected equivocations in equivocated set by adding id of the voter there.
  3. If it's only first time we observe this voter equivocating — we continue.
  4. If we've already seen the voter equivocating — we return.

validation_result.valid is false in this case (default value).

  1. If we detect duplicates, they don't affect validity status.

  2. In the end, validity status is set to true if we computed valid GHOST.

So, validate_commit still can succeed even in presence of equivocations.


I've scanned GRANDPA docs, W3F website and GitHub issues but couldn't find anything about tolerance to equivocations. Please, could anyone clarify it to me?

Are the following statements correct?

  1. The method validate_commit is intended to be used in a light client.
  2. Successful status of validate_commit, i.e. CommitValidationResult::valid == true, means that the header containing it CAN be accepted and update the light client.
  3. Failed status of validate_commit, i.e. CommitValidationResult::valid == false, means that the header containing this proof MUST NOT be accepted.
  4. Equivocations are forbidden in any amount, all voters from equivocated set must get slashed.
  5. Equivocations don't make the finality proof invalid.
  6. Finality proof SHOULD contain equivocations if there been any. This "seals" fact of misbehaviour into the blockchain.
  7. Finality proof MUST NOT contain more than 1 equivocation for a voter, this is important because we don't want to bloat the proofs.

Probably, all of the above is correct, or none of it.

Please, make it clear!

1 Answer 1


GRANDPA tolerates up to 1/3 of the validator set equivocating. Whenever a voter equivocates that is counted as voting for everything (quoting from the paper: "We count equivocations as votes for everything so that observing a vote is monotonic"), that is why we need to track equivocations when validating a justification since they contribute as a "vote" for something to get finalized. Since an equivocation is counted as voting for everything we only care about keeping track of a single equivocation per voter, adding more equivocated votes for the same voter to the justification would just be unnecessary bloat. The method validate_commit is meant to be used by anyone that wants to validate a commit, both full and light clients will do this. Equivocators do get slashed but that isn't dealt with here, we only detect equivocations and report them to staking.

  • Thank you Andre. I haven't thought about that equivocations are votes for all branches. So if a relayer cuts them from a proof, then it's not even possible to verify the proof properly, right? Jun 7 at 15:37
  • 1
    It depends, e.g. if we have 100 voters and we get 70 valid votes and 1 equivocated vote then you can create a valid justification just using 67 valid votes. But e.g. if we have 66 valid votes and 1 equivocated vote (let's assume the other 33 validators were offline) then the equivocation is indeed crucial to finalize the block (and hence should be part of the justification).
    – André
    Jun 13 at 11:01

Your Answer

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

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