linera-io/linera-protocol · error · ChainError
JustificationCommitmentMismatch
JustificationCommitmentMismatch
Error message
Certificate justification commitment does not match its justification chain
What it means
Thrown by check_cited_quorum when the opening quorum's value_hash does not equal the hash of the block header the vote was for (ChainError::JustificationCommitmentMismatch). A vote's justification commitment signs an opening that must validate the same block the vote is about; an opening over a different block cannot ground the vote. This is one of the specific reasons an InvalidJustification equivocation proof is considered genuine — a validator signing a commitment to an opening about a different block is at fault.
Source
Thrown at linera-chain/src/justification/mod.rs:614
}
}
}
/// Checks that `opening` is a quorum an honest voter could cite from a vote of the given kind,
/// round and unlocking round for the block with the given header: it validates the same block, in
/// the round the vote's payload grounds on, and its signatures form a genuine quorum of
/// `committee` over the reconstructed `ValidatedBlock` payload. These are exactly the checks a
/// voter performs before signing the opening's commitment, so their failure on a signed opening
/// convicts the signer.
fn check_cited_quorum(
header: &BlockHeader,
round: Round,
kind: CertificateKind,
unlocking_round: Option<Round>,
opening: &CommittedQuorum,
committee: &Committee,
) -> Result<(), ChainError> {
ensure!(
opening.value_hash == CryptoHash::new(header),
ChainError::JustificationCommitmentMismatch
);
match kind {
// A validated vote cites the quorum grounding its unlocking round, in a lower round.
CertificateKind::Validated => ensure!(
unlocking_round == Some(opening.round) && opening.round < round,
ChainError::JustificationUnlockingRoundMismatch
),
// A confirmed vote cites the quorum that validated the block in the same round.
CertificateKind::Confirmed => ensure!(
opening.round == round,
ChainError::JustificationUnlockingRoundMismatch
),
// Timeout votes cite nothing; any commitment is dishonest.
CertificateKind::Timeout => ensure!(false, ChainError::JustificationCommitmentMismatch),
}
// A quorum with an unlocking round cites a quorum itself, and vice versa: its own commitmentView on GitHub (pinned to 6c226ddcb3)
Solutions
- If you are a voter: only sign a justification commitment computed over the same block you are voting on (recompute chain.commitment(CryptoHash::new(&header))).
- If you are verifying: treat this mismatch as attributable misbehavior — report an InvalidJustication proof with the opening as evidence.
- If building certificates, derive the opening from the block's own validation path, never from a cached chain of another block.
- In tests, ensure headers and openings are generated from the same block.
Defensive patterns
Strategy: validation
Validate before calling
ensure!(
opening.value_hash == CryptoHash::new(&header),
"justification opens a different block than the vote is for"
); Try / catch
match check_cited_quorum(header, round, kind, unlocking_round, &opening, committee) {
Err(ChainError::JustificationCommitmentMismatch) => {
// attributable fault: build an InvalidJustification proof with this opening
let proof = EquivocationProof::InvalidJustification { validator, header: header.clone(), round, kind, unlocking_round, first_round, signature, opening };
report_fault(proof);
Err(anyhow::anyhow!("voter cited a justification for a different block"))
}
other => other,
} Prevention
- As a voter, compute the justification commitment over your own block's hash: chain.commitment(CryptoHash::new(&header)).
- Never reuse a justification chain from another block.
- Bind headers and openings together at construction time in the same function.
When it happens
Trigger: Calling check_cited_quorum (directly, or via EquivocationProof::check on an InvalidJustification proof) where opening.value_hash != CryptoHash::new(header). In honest certificate flow this appears if a voter cites a justification chain for a different block; in proof flow it is the expected condition that convicts the signer.
Common situations: Voters copying a justification from a different block's context; certificate-building code pairing headers with the wrong CommittedQuorum; slashing evidence where the mismatch is the fault being proven.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- EquivocationProofValidJustification
- Signatures in a certificate must form a quorum
- JustificationUnlockingRoundMismatch
- no signer found for owner ${owner}
- CannotRejectMessage
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/f31033f53a3933ed.
Report an issue: GitHub.