-
Notifications
You must be signed in to change notification settings - Fork 32
Description
Status quo
Currently, when ticking a ledger state across an era boundary in the HFC, we use the translate-then-tick strategy.
Click to see current implementation details
HFC ticking is implemented here:
https://github.com/input-output-hk/ouroboros-consensus/blob/0ca9ca08f41b04619dc9ed1df692102ef9ba3c0e/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Ledger.hs#L121-L154
Note that we first translate in extendToSlot
if the target slot is in a new era:
https://github.com/input-output-hk/ouroboros-consensus/blob/0ca9ca08f41b04619dc9ed1df692102ef9ba3c0e/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/State.hs#L212
https://github.com/input-output-hk/ouroboros-consensus/blob/0ca9ca08f41b04619dc9ed1df692102ef9ba3c0e/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/State.hs#L226-L228
This means that when we tick a ledger state s
in era FromEra
(which arose by applying a block with slot x
) to a slot y
in the next era ToEra
, we
- first translate the
FromEra
ledger states
to aToEra
ledger states'
(s'
is now aFromEra
ledger state, even though its tip slotx
hasn't moved, so is still before the era boundary), and - then tick
s'
to sloty
,
yielding the ledger state s'''
we can use to validate blocks in slot y
.
In the following diagram, this means that we start at s
, first go right and then down.
╔══════════════╦═════════════════════════════════════╗
║ Time \ Era ║ FromEra ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌⇢ ToEra ║
╠══════════════╬═════════════════════════════════════╣
║ Start - x ║ s ──── translate ────────→ s' ║
║ ┊ ║ │╲ │ ║
║ ┊ ║ tick ╲tick tick ║
║ Boundary ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ║
║ ┊ ║ │ s' ── translate ─→ s'' │ ║
║ ┊ ║ │ ╲ │ ║
║ ┊ ║ │ tick╲ │ ║
║ ┊ ║ │ ╲ │ ║
║ ⇣ ║ ↓ ↘↓ ║
║ Target - y ║ s' ─── translate ────────→ s''' ║
╚══════════════╩═════════════════════════════════════╝
Why the status quo is problematic
The current behavior is causing IntersectMBO/cardano-ledger#3491; we need some context how Ledger handles updates to the on-chain protocol parameters before Voltaire (ie in all Shelley-based eras before Conway):
- At every epoch boundary, the protocol parameters can change if sufficiently many Genesis keys submit the same update proposal.
- This logic is handled by the UPEC rule, which is executed when eg ticking.
This mechanism changed completely in Conway; in particular, there is no direct analogue to update proposals signed by Genesis keys. This means that all such proposals are discarded when translating a Babbage ledger state to a Conway ledger state.
Hence, as we currently first translate and then tick, the Conway logic responsible for ticking has no way of knowing that it should update the protocol version (or any other updateable parameter).
Proposed change
In this issue, we suggest to change the HFC cross-era ticking to the tick-then-translate-then-tick approach, ie first tick to the epoch boundary, then translate the ledger state, and then tick to the requested slot.
In more detail: In order to tick a ledger state s
(with tip x
) in era FromEra
to a slot y
in the next era ToEra
, we
- first tick the ledger state
s
to the first slot inFromEra
, yielding a ledger states'
, - then translate the
FromEra
ledger states'
to aToEra
ledger states''
, and - finally tick the ledger state
s''
to sloty
again yielding the desired ledger state s'''
.
In the diagram above, we again start at s
, tick by moving diagonally to s'
, then translate by moving horizontally to s''
, and finally tick again by moving diagonally to s'''
.
This way, we use the FromEra
logic to tick across the era/epoch boundary, which can then execute the UPEC rule in the example above.
Slogan: Cross-era ticking is fundamentally something that happens at the end of an era, so it should be done using the logic of that ending era.
Alternatives
We considered the following alternatives:
-
Use the tick-then-translate apprach, ie tick directly to the target slot, and then translate.
While this would probably work fine with existing any likely also with future eras, it seems wrong to use the ticking logic of the old era to let time pass across slots that lie purely within the new era. Also, we again have (just before translating) a ledger state in the "wrong" era as with the current translate-then-tick approach.
-
Don't change the HFC logic at all, but rather introduce an ad-hoc field in the Conway ledger state that records the Babbage update proposals, such that they can be preserved by translating.
This seems quite ugly, ie this field would only be present in the first Voltaire era, and it would require ledger rule logic that is purely related to era transitions, which is something that the ledger rules usually do not have to handle explicitly.
Remarks
Note that the HFC mechanism that detects whether we should transition in the first place (see singleEraTransition
) is not affected by this bug; we still properly transition from Babbage to Conway.