Skip to main content
The Sundial L2’s consensus protocol is implemented entirely as L1 smart contracts. It establishes the canonical chain of valid blocks. Its parts:

Operators

Operators receive L2 transactions, assemble blocks, publish the full blocks to the data availability layer, and commit the headers to the state queue. They share this job on a rotating schedule.

Lifecycle

  1. Register. Anyone can register by posting the required bond in ADA.
  2. Wait. A registrant waits registration_duration before activating. If the active set is empty, the earliest registrant activates at once.
  3. Active. The operator takes its turn in the schedule.
  4. Retire. An active operator can retire. It recovers its bond only after all its committed headers have matured.

Bond and slashing

The bond backs the operator’s promise to commit valid blocks. An operator whose header is proven fraudulent is disqualified and forfeits the bond. The forfeited bond is split:
  • fraud_prover_reward goes to the watcher that proved the fraud.
  • slashing_penalty goes to the settlement L1’s treasury.
The two always sum to required_bond. For a network that secures value, the design range is a bond of 50,000 to 200,000 ADA with 30% to 50% of it as the prover’s reward.

Inactivity

Operators that don’t commit blocks during their shift, or ignore user events, receive strikes. After max_inactivity_strikes, part of the bond is slashed and the operator is retired.

Time model

Time is divided in two independent ways.
  • Shifts are fixed intervals of shift_duration, assigned to operators by the scheduler. Only the appointed operator can commit blocks.
  • Event intervals are the intervals [start_time, end_time) that blocks claim. A block’s start_time is the previous block’s end_time. Its end_time is the upper bound of the validity range of its commitment transaction.
Because each interval starts where the last one ended, intervals cover time with no gaps or overlaps. And because a commitment transaction is only valid while L1 time is inside its validity range, an operator can’t claim an interval far in the future or let it lag behind the clock.
An interval can span a shift boundary. An operator can commit blocks as quickly as it likes during its shift.

Scheduler

The scheduler is one L1 UTXO that names the current operator and its shift start. It steps through the active operators in order. At the end of each cycle, registered operators that are eligible must activate before the next cycle starts. The shift only controls when the scheduler advances. If the next operator is inactive, the current one can keep committing.

State queue

The state queue is an L1 linked list of block headers. Its root node holds the confirmed state. It has three operations:
  • Commit. The appointed operator appends a header to the end of the queue. The contract checks the operator’s signature, the link to the previous header, and the time bounds.
  • Merge. After maturity_duration, the header at the front of the queue is merged into the confirmed state. Blocks merge in order.
  • Remove. When a fraud proof succeeds, the fraudulent header and its descendants are removed, descendants first.
After a removal, the next committed header starts where the last remaining one ended. Its interval covers the removed blocks’ intervals, so it must include every user event they should have included.

Settlement

When a block that contains deposits, withdrawals or transaction orders merges, a settlement UTXO is created holding that block’s event roots. Users reference it to absorb confirmed deposits into the reserve and to start payouts for confirmed withdrawals. The current operator can attach a resolution claim to a settlement UTXO, stating that all its events have been processed. The claim waits for maturity_duration. If it is proven false in that time, the operator is slashed. Otherwise the operator can spend the settlement UTXO and recover its deposit and some fees. An operator’s bond stays locked until all its headers and all its resolution claims have matured.

Escape hatch

The escape hatch restores block production when operators have stopped committing blocks. It trades some security for liveness, for a bounded time.
1

Trigger

Anyone can trigger it once the last header in the state queue is older than escape_hatch_block_age. This is possible only when every active operator has stopped.
2

Emergency period

For emergency_duration, new operators can register with the lower emergency_required_bond, so that honest actors can restart production cheaply.
3

Recovery

A grace period of emergency_grace_period follows. A reduced-bond operator can retire, or top its bond up to required_bond and stay. After the grace period, anyone can retire an operator that is still under-bonded and claim a small penalty from its bond.
The escape hatch doesn’t change the time model. The first block after an outage has an interval that spans the outage, so it must include every deposit, withdrawal order and transaction order created during it. User funds are not stranded by an outage of any length.
The escape hatch is a mechanism for operators. It is not a button that withdraws your funds directly. You exit with a withdrawal order, which the restarted operators must include.

Parameters

Every name in code font on this page is a protocol parameter. Protocol parameters lists them with their design ranges.