Files
dex/pkg
zeekayandHanzo Dev 52905e489a dchain: genesis is its own construction, not a block with an empty parent
Height 0 was built by calling the block composition with the creation
document's digest in the slot that means "parent" everywhere else. The slot
was unused, so the convention held — and nothing enforced it. When the custody
ledger entered ComposeRoot in v1.14.0 every chain's genesis moved with it,
silently, because genesis was downstream of a composition that has nothing to
do with chain identity.

Genesis now has its own domain-separated construction and no longer touches
the block root:

    GenesisDigest = keccak256("dex/genesis/v1"      | init.Genesis)
    GenesisRoot   = keccak256("dex/genesis-root/v1" | digest | book | trade | tx | ledger)
    BlockRoot     = keccak256("dex/block-root/v1"   | parent | book | trade | tx | ledger | height)

Different creation document -> different digest -> different genesis root ->
different root at every descendant height. That is now structural rather than
a property of a field that happens to be free.

GenesisDigest is defined for every input including none, so a running chain
always has one; whether a chain may run without a creation document is a
policy question and stays where it was answered.

The vectors verify the derivation against the written construction, using a
separate keccak and the empty sub-roots read from pinned hex, so they do not
drift by being updated to match. They also hold the three fleet documents to
their on-chain sha256, and pin the genesis against a VM carrying arbitrary
runtime state: same bytes in, same chain out, whatever the binary is doing.

Perturbing the block root now leaves every fleet genesis unmoved; routing
genesis back through the block composition fails the vector.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-07 16:44:15 -07:00
..