Skip to main content

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:

  1. Erasure Coding: Guarantors chunk the work-package into erasure-coded segments
  2. Distribution: Segments distributed to all validators
  3. Assurances: Validators attest they have their chunks (see Assurances)
  4. Availability: Once ≥⅔ validators assure, report becomes available
  5. 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 logic
  • guarantee_assignment.py: Core-to-validator assignment
  • error.py: Report-specific errors

Process:

  1. Validate guarantee sorting and structure
  2. Verify all guarantor signatures
  3. Check core availability and authorization
  4. 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