linera-io/linera-protocol · error · ChainError

EquivocationProofNoFirstRoundViolation

EquivocationProofNoFirstRoundViolation

Error message

Equivocation proof's earlier vote is not below the attested first round

What it means

Thrown by EquivocationProof::check for a FirstRoundViolation proof when the earlier vote's round is not strictly below the attested round (ChainError::EquivocationProofNoFirstRoundViolation). The proof's logic is that the validator attested 'this is the first round at this height' while having already voted in a lower round at that height; if earlier_round >= attested_round there is no contradiction. Note the earlier vote may itself carry an attestation — only the rounds are compared here.

Source

Thrown at linera-chain/src/justification/mod.rs:543

                attested_round,
                attested_commitment,
                attested_signature,
                earlier_header,
                earlier_round,
                earlier_attested,
                earlier_commitment,
                earlier_signature,
            } => {
                // Both votes must concern the same height on the same chain: the attestation only
                // asserts that no lower round exists at *this* height, so a vote at a lower round
                // number elsewhere does not contradict it. The blocks themselves may be equal —
                // the contradiction is between the rounds, not the blocks.
                ensure!(
                    attested_header.chain_id == earlier_header.chain_id
                        && attested_header.height == earlier_header.height,
                    ChainError::EquivocationProofDifferentChainOrHeight
                );
                ensure!(
                    *earlier_round < *attested_round,
                    ChainError::EquivocationProofNoFirstRoundViolation
                );
                let attested = VoteValue(
                    CryptoHash::new(attested_header),
                    *attested_round,
                    CertificateKind::Confirmed,
                    None,
                    true,
                    *attested_commitment,
                );
                attested_signature.check(&attested, *validator)?;
                let earlier = VoteValue(
                    CryptoHash::new(earlier_header),
                    *earlier_round,
                    CertificateKind::Confirmed,
                    None,
                    *earlier_attested,

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Assert earlier_round < attested_round before constructing the proof.
  2. When scanning, select as 'earlier' the vote with the strictly smaller round at the same (chain, height).
  3. If the rounds are equal or reversed, drop the pair — no violation is provable from it.
  4. Double-check which vote carries first_round == true; the attested one must be the higher round.

Example fix

// before
let proof = FirstRoundViolation { attested_round: r1, earlier_round: r2, .. }; // r2 > r1
proof.check(&committee)?; // Err

// after
if earlier_round >= attested_round {
    (attested, earlier) = (earlier, attested); // only if the attestation is on the higher round
}
ensure!(earlier_round < attested_round, "no contradiction between rounds");
let proof = FirstRoundViolation { attested_round, earlier_round, .. };
Defensive patterns

Strategy: validation

Validate before calling

ensure!(
    earlier_round < attested_round,
    "earlier vote must be strictly below the attested round"
);

Try / catch

match proof.check(committee) {
    Err(ChainError::EquivocationProofNoFirstRoundViolation) => {
        // no contradiction between rounds: discard the proof
        Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: Submitting a FirstRoundViolation where earlier_round >= attested_round — e.g. pairing the attested vote with a vote in the same or a higher round, or mixing up which of the two votes carries the attestation during extraction.

Common situations: Evidence collectors pairing an attestation with a later vote instead of an earlier one; mislabeled fields when building the proof struct; tests using equal Round values for both votes.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/fb9da7c31b7a39cd. Report an issue: GitHub.