Skip to content

refactor(chain): commit block digest over a transaction root#131

Open
erenyegit wants to merge 1 commit into
mainfrom
refactor/block-header-digest
Open

refactor(chain): commit block digest over a transaction root#131
erenyegit wants to merge 1 commit into
mainfrom
refactor/block-header-digest

Conversation

@erenyegit

Copy link
Copy Markdown
Collaborator

What

Fold a block's transactions into a domain-separated transaction root and
commit the block digest over that root instead of inlining every transaction.
Add a compact, digest-authenticated BlockHeader that carries every
non-transaction digest field plus the transaction root, so a verifier can
reproduce and check a block's digest without the full block, then read the
authenticated state_root / state_range out of it.

This is the foundation the bridge's certified checkpoint needs: to authenticate
a foreign chain's state root from a finalization certificate (which signs a
block digest), the verifier must recompute that digest from a compact header
rather than the entire block.

Changes

  • Transaction root computation — domain-separated sequential-hash commitment over
    the ordered transaction list.
  • Block digest now commits over the transaction root (via a shared
    block_digest), not the inlined transactions.
  • BlockHeader<Ext> — context, parent, height, timestamp, transaction_root,
    reshare_log, extension, state_root, state_range + codec.
  • Block::header() and BlockHeader::digest() (reproduces the source block's
    digest exactly).

Consensus-breaking

This changes every block's digest and must land before testnet.

Note on naming

The transaction root is a sequential-hash commitment, not a Merkle tree: it
authenticates the exact ordered transaction list (count, order, and bytes all
matter) but does not support per-transaction inclusion proofs.

Tests (chain/tests/block_header.rs)

  • block.header().digest() == block.digest()
  • changing a transaction changes the root and digest
  • reordering transactions changes the root and digest
  • empty vs non-empty transaction lists differ
  • changing state_root / state_range changes the header digest
  • header codec round-trips

Follow-up

The bridge certified-checkpoint PR builds on this: the consensus extension will
verify a foreign finalization certificate against a BlockHeader and store
checkpoint_id -> state_root + state_range.

Fold a block's transactions into a domain-separated transaction-root
commitment and commit the block digest over that root instead of inlining
every transaction. This lets a compact BlockHeader reproduce and check the
block digest without carrying the transactions, then read the authenticated
state_root/state_range out of it — the foundation the bridge's certified
checkpoint needs to authenticate a foreign state root from a finalization
certificate.

Add BlockHeader (every non-transaction digest field plus the transaction
root), Block::header(), and BlockHeader::digest(), which reproduces the
source block's digest exactly.

The transaction root is a sequential-hash commitment, not a Merkle tree: it
authenticates the exact ordered transaction list (count, order, and bytes)
but does not support per-transaction inclusion proofs.

BREAKING: this changes every block's digest and is consensus-breaking; it
must land before testnet.
@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
chain/src/block.rs 92.85% 0 Missing and 9 partials ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant