Disputes
The Disputes transition processes verdicts (collections of judgments from validators), registers offenses, and removes invalid work-reports from the processing pipeline.
Purpose
- Verdict Registration: Record consensus among ≥⅔ validators about a work-report's validity
- Offense Recording: Permanently record misbehaving validators (guarantors who signed invalid reports, or validators whose judgments contradict verdicts)
- Invalid Report Removal: Ensure work-reports judged invalid are not accumulated or resubmitted
- Punishment Coordination: Provide on-chain record for higher-level slashing/banning logic
Key Concepts
Judgments
Judgments are signed statements from validators about a work-report's validity, created during the off-chain auditing process (see Auditing). Validators audit work-reports and produce judgments (valid/invalid).
Verdicts
A verdict is a collection of exactly ⅔ + 1 judgments from either the current or previous validator set, representing consensus on a work-report's validity.
Offenses
Two types of offenses can be proven on-chain:
- Culprits: Validators who guaranteed a work-report later found invalid
- Faults: Validators whose judgments contradict an established verdict
State Structure
ψ ≡ ⟨ψ_g, ψ_b, ψ_w, ψ_o⟩
ψ_g: Set<H> // Good set - reports judged valid
ψ_b: Set<H> // Bad set - reports judged invalid
ψ_w: Set<H> // Wonky set - reports impossible to judge
ψ_o: Set<Ed25519> // Offenders - misbehaving validator keys
Disputes Extrinsic
E_D ≡ ⟨verdicts, culprits, faults⟩
Verdict {
report_hash: H,
epoch_index: u32, // Current or previous epoch
judgments: [(bool, u16, Sig)] // ⅔+1 judgments
}
Culprit {
report_hash: H, // Must be in bad set
validator_key: Ed25519,
signature: Ed25519Sig // Guarantee signature
}
Fault {
report_hash: H,
validity: bool, // Validator's claimed validity
validator_key: Ed25519,
signature: Ed25519Sig // Judgment signature contradicting verdict
}
How It Works
1. Verdict Classification
Based on positive vote count:
positive_votes = sum(1 for (valid, _, _) in judgment if valid)
supermajority = floor(2 * VALIDATOR_COUNT / 3) + 1
if positive_votes == len(judgments): // All positive
verdict_type = "good"
psi.good_set.add(report_hash)
elif positive_votes == 0: // All negative
verdict_type = "bad"
psi.bad_set.add(report_hash)
elif positive_votes >= VALIDATOR_COUNT / 3: // Mixed, unclear
verdict_type = "wonky"
psi.wonky_set.add(report_hash)
else:
raise Error("Invalid vote split")
2. Offense Processing
Culprits (guaranteed an invalid report):
for (report_hash, validator_key, signature) in block.extrinsic.culprits:
# Verify: report is in bad set
assert report_hash in psi.bad_set
# Verify signature matches guarantee
verify_signature(validator_key, b"$jam_guarantee" + report_hash, signature)
# Add to offenders
psi.offenders.add(validator_key)
Faults (judgment contradicts verdict):
for (report_hash, claimed_validity, validator_key, sig) in block.extrinsic.faults:
# Check contradiction
if report_hash in psi.bad_set:
assert claimed_validity == True // Claimed valid but verdict says bad
elif report_hash in psi.good_set:
assert claimed_validity == False // Claimed invalid but verdict says good
# Verify judgment signature
verify_signature(validator_key, b"$jam_valid" + report_hash, sig)
# Add to offenders
psi.offenders.add(validator_key)
3. Pending Work-Report Removal
Remove work-reports from pending state (ρ) if they received negative verdicts:
for core in range(341):
if rho[core] is not None:
report_hash = hash(rho[core].report)
if report_hash in psi.bad_set or report_hash in psi.wonky_set:
rho[core] = None // Remove invalid/uncertain reports
4. Chain Reversion
A negative judgment implies the chain should revert to before the work-report's accumulation. Chain selection logic (see Best Chain) handles this automatically by prioritizing chains without disputed reports.
Validation Rules
Verdicts
- Sorted by report_hash (ascending)
- Judgments within each verdict sorted by validator index
- Exactly ⅔ + 1 judgments (floor(2V/3) + 1)
- All signatures valid for current or previous epoch validators
- No duplicate report hashes across all past verdicts
Culprits & Faults
- Sorted by validator key (ascending)
- No duplicate validator keys
- Referenced reports must have verdicts
- Validator keys not already in offenders set
- All signatures valid
Security Properties
Permanent Record
Once a verdict is registered, it's permanent - prevents:
- Resubmission of invalid reports
- Future disputes on already-judged reports
- Uncertainty about report validity
Misbehavior Tracking
Offenders list provides simple basis for:
- Removing validators from future sets (see SAFROLE validator rotation)
- Higher-level slashing logic (e.g., Polkadot staking parachain)
- Coordination across the network
Consensus Safety
⅔ + 1 threshold ensures:
- At least ⅓ + 1 honest validators agree
- Byzantine fault tolerance maintained
- Cannot be manipulated by ≤⅓ malicious validators
Implementation Details
Location: tessera/jam/state/transitions/disputes/
Key Files:
disputes.py: Main transition logicDisputes.md: Detailed specificationerror.py: Dispute-specific errors
Process:
- Validate verdict sorting and signatures
- Classify verdicts as good/bad/wonky based on vote counts
- Process culprits and faults, verify signatures
- Update ψ sets (good, bad, wonky, offenders)
- Remove disputed reports from ρ (pending work-reports)
Constants:
- Supermajority = floor(2 * 1023 / 3) + 1 = 682 + 1 = 683 judgments
Relationship to Auditing
Important: The actual validation of work-reports happens off-chain during the auditing process:
- Validators audit assigned work-reports (off-chain)
- Validators sign judgments about validity (off-chain)
- If negative judgments emerge, validators collect ⅔ + 1 judgments
- Verdict is submitted on-chain (this transition processes it)
The disputes transition does NOT re-execute or validate work - it only processes the verdicts from off-chain auditing.
Error Conditions
class DisputesErrorCode:
VERDICT_ALREADY_JUDGED // Report hash already in ψ sets
INVALID_AGE // Epoch index not current or previous
BAD_VOTE_SPLIT // Vote count doesn't match good/bad/wonky criteria
INVALID_SIGNATURE // Ed25519 signature verification failed
NOT_SORTED // Verdicts/culprits/faults not properly ordered
CONTRADICTORY_FAULT // Fault doesn't contradict the verdict
References
- Gray Paper: Section on Disputes, Verdicts and Judgments
- Auditing: See Auditing for off-chain judgment process
- Implementation:
tessera/jam/state/transitions/disputes/
Next: Reports | Accumulation