Reports
The Reports transition processes work-report guarantees from validators, adding them to pending state where they await availability assurances.
Purpose
- Guarantee Processing: Accept work-reports signed by assigned validators (guarantors)
- Core Assignment: Place work-reports on cores, ensuring cores aren't double-booked
- Authorization Validation: Verify work-report authorizers are valid for the target core
- Pending State Management: Track reports awaiting availability confirmation
State Structure
ρ ∈ [Option<WorkReportState>; 341] // Pending reports per core
WorkReportState {
work_report: WorkReport,
timestamp: Slot // When report was guaranteed
}
Guarantees Extrinsic
E_G ∈ [Guarantee; ≤341] // At most one guarantee per core
Guarantee {
work_report: WorkReport,
timeslot: Slot,
credential: [(u16, Ed25519Sig); 2..3] // 2-3 guarantor signatures
}
Key points:
- Each guarantee contains 2-3 Ed25519 signatures from validators
- Validators must be assigned to that core during the timeslot
- Signatures are on the Blake2b hash of the serialized work-report
- Guarantees must be sorted by core index (ascending)
How It Works
1. Guarantor Assignment
Validators are assigned to cores via a rotation mechanism. Only validators assigned to a core can guarantee work for it:
# Check if validator is assigned to this core
assigned_validators = get_core_assignments(core, timeslot)
for (validator_index, signature) in guarantee.credential:
assert validator_index in assigned_validators[core]
2. Signature Verification
Each guarantor signs the work-report hash:
def verify_guarantee(guarantee):
report_hash = blake2b(encode(guarantee.work_report))
message = b"$jam_guarantee" + report_hash
for (validator_index, signature) in guarantee.credential:
validator_key = validators[validator_index].ed25519
verify_ed25519(validator_key, signature, message)
3. Core Availability Check
Cores can only hold one pending report at a time:
for guarantee in block.extrinsic.guarantees:
core = guarantee.work_report.core
# Core must be empty or timed out
assert rho[core] is None
4. Authorization Check
The work-report's authorizer must be in the core's authorization pool:
work_report = guarantee.work_report
assert work_report.authorizer_hash in alpha[work_report.core]
5. Adding to Pending State
rho[work_report.core] = WorkReportState(
work_report=work_report,
timestamp=guarantee.timeslot
)
Validation Rules
Guarantee Extrinsic
- At most one guarantee per core (max 341 guarantees)
- Sorted by core index (ascending)
- No duplicate cores
Credentials
- 2-3 validator signatures required
- Validators must be uniquely indexed
- Sorted by validator index (ascending)
- All signatures must be valid Ed25519 signatures
Work-Report
- Core must be available (no pending report)
- Authorizer must be in authorization pool
α[core] - Total accumulation gas ≤ limit
- Each work-digest gas ≥ service minimum
Timeslot
- Must be within valid rotation period
- Guarantors must be assigned to core during this timeslot
Complete Validation
def validate_and_process_guarantees(state, block):
guarantees = block.extrinsic.guarantees
# Guarantees sorted by core
assert guarantees == sorted(guarantees, key=lambda g: g.work_report.core)
for guarantee in guarantees:
wr = guarantee.work_report
# 1. Check credential
assert len(guarantee.credential) in [2, 3]
assert is_sorted_unique(guarantee.credential, key=lambda c: c[0])
# 2. Verify signatures
for (validator_idx, sig) in guarantee.credential:
verify_guarantor_signature(validator_idx, wr, sig, guarantee.timeslot)
# 3. Core available
assert state.rho[wr.core] is None
# 4. Authorizer valid
assert wr.authorizer_hash in state.alpha[wr.core]
# 5. Add to pending
state.rho[wr.core] = WorkReportState(
work_report=wr,
timestamp=guarantee.timeslot
)
return state
Next Steps
After a work-report is guaranteed:
- Erasure Coding: Guarantors chunk the work-package into erasure-coded segments
- Distribution: Segments distributed to all validators
- Assurances: Validators attest they have their chunks (see Assurances)
- Availability: Once ≥⅔ validators assure, report becomes available
- Accumulation: Available reports are integrated into service state (see Accumulation)
Timeout
If a report doesn't receive sufficient assurances within 8 slots (48 seconds), it times out and the core becomes available for a new report.
Implementation Details
Location: tessera/jam/state/transitions/report/
Key Files:
reporting.py: Guarantee processing logicguarantee_assignment.py: Core-to-validator assignmenterror.py: Report-specific errors
Process:
- Validate guarantee sorting and structure
- Verify all guarantor signatures
- Check core availability and authorization
- Add to pending state ρ
References
- Gray Paper: Section on Work Report Guarantees
- Guaranteeing: Section on off-chain guarantee creation
- Implementation:
tessera/jam/state/transitions/report/
Next: Assurances | Accumulation