Skip to content

refactor(vara.eth): introduce typed MB/EB hashes, move MB to ethexe-common#5508

Draft
grishasobol wants to merge 4 commits into
gsobol/ethexe/malachite-core-concretize-payloadfrom
gsobol/ethexe/malachite-typed-block-hashes
Draft

refactor(vara.eth): introduce typed MB/EB hashes, move MB to ethexe-common#5508
grishasobol wants to merge 4 commits into
gsobol/ethexe/malachite-core-concretize-payloadfrom
gsobol/ethexe/malachite-typed-block-hashes

Conversation

@grishasobol
Copy link
Copy Markdown
Member

Summary

  • Move the consensus block envelope (ethexe_malachite_core::Blockethexe_common::malachite::MB), the versioned BlockPayload, and CompactMb into ethexe-common so the executor crates can use them without depending on the consensus layer.
  • CompactMb now matches MB's shape with the opaque payload replaced by payload_hash (renamed from transactions_hash).
  • Type-safe hashes for boundary fields: HashOf<MB> on CompactMb.parent, BlockMeta.last_committed_mb, DBGlobals.{latest_finalized_mb_hash, latest_computed_mb_hash}; HashOf<EB> on MbMeta.last_advanced_eb, BlockMeta.last_committed_eb, DBGlobals.{start_block_hash, latest_prepared_eb_hash}, DBConfig.genesis_block_hash.
  • New pub type EB = SimpleBlockData + SimpleBlockData::typed_hash() / eb_hash_of(H256) to lift the bare Ethereum block hash into the typed wrapper.
  • HashOf<T> is Encode + Decode as a bare 32-byte hash (phantom is #[codec(skip)]), so the on-wire/on-disk layout is byte-identical to before — only the static type at the field changes.
  • MbStorageRO/RW trait method parameters intentionally keep mb_hash: H256. Threading HashOf<MB> through every call site in compute/cli/consensus/processor/etc. would cascade through dozens of files for no extra safety gain — the boundary structs already catch the EB-vs-MB confusion that motivated the refactor. Call sites pass field.inner() where needed.

Fixes #5507.

Test plan

  • cargo nextest run -p ethexe-common -p ethexe-db -p ethexe-malachite-core -p ethexe-malachite -p ethexe-compute -p ethexe-consensus — 248/248 pass (incl. multi-validator integration tests).
  • cargo fmt, cargo clippy --workspace --tests — clean.
  • ensure_types_unchanged updated with the new EXPECTED_TYPE_INFO_HASH (CompactMb shape changed).
  • CI green.

🤖 Generated with Claude Code

@grishasobol grishasobol added type: refactor Internal improvements without changing behavior scope: vara.eth Vara Ethereum application layer (L2) ai-friendly Suitable for AI-assisted implementation or review labels May 22, 2026
@grishasobol grishasobol self-assigned this May 22, 2026
@grishasobol grishasobol added the ai-friendly Suitable for AI-assisted implementation or review label May 22, 2026
@grishasobol grishasobol force-pushed the gsobol/ethexe/malachite-core-concretize-payload branch from 733e281 to eca538f Compare May 25, 2026 10:54
@grishasobol grishasobol force-pushed the gsobol/ethexe/malachite-typed-block-hashes branch from 2b05f34 to a5e2859 Compare May 25, 2026 11:06
grishasobol added a commit that referenced this pull request May 25, 2026
PR #5508 left MbStorageRO/RW and OnChainStorageRO/RW + BlockMetaStorageRO/RW
methods taking raw H256, which forced every caller to thread untyped hashes
and use `.inner()` at boundaries. Type the signatures end-to-end so the
typed values flow through the codebase: EB-block hashes become
`HashOf<EB>`, MB hashes become `HashOf<MB>`. CAS payload hashes
(`set_transactions` return, `transactions(payload_hash)`) stay raw H256
since they're content-addressed, not entity-addressed.

The cascade is real — ~30 files touched across ethexe/common, ethexe/db,
ethexe/compute, ethexe/consensus, ethexe/malachite/service,
ethexe/network, ethexe/observer, ethexe/prometheus, ethexe/rpc and
ethexe/service. Where a function receives raw H256 from an external
source (chain events, malachite-core API, test fixtures) we still cross
the typed boundary with a local `mb_h` / `eb_h` helper rather than
making `HashOf::new` safe, so each conversion remains explicit and
auditable.

`Mirror.processOutgoingAction` flow and existing tests continue to
compile and lint clean across the workspace.
@grishasobol
Copy link
Copy Markdown
Member Author

Pushed refactor to type DB trait signatures with HashOf<EB>/HashOf<MB> end-to-end (32 files, +628/-411). MbStorageRO/RW, OnChainStorageRO/RW and BlockMetaStorageRO/RW now take typed values; .inner() only at the explicit boundary with external systems (chain events, malachite-core API, test fixtures).

CI: https://github.com/gear-tech/gear/actions/runs/26400404637

@grishasobol grishasobol force-pushed the gsobol/ethexe/malachite-core-concretize-payload branch from fbd5c67 to d3341a6 Compare May 25, 2026 17:15
…d to ethexe-common

Move the consensus block envelope `MB` (formerly `ethexe_malachite_core::Block`),
the versioned `BlockPayload`, and the on-disk `CompactMb` shape into
`ethexe_common::malachite` so the executor (`ethexe-compute`, etc.)
can reason about them without depending on the consensus layer.

Type-safe MB / EB hashes:
- `CompactMb { parent: HashOf<MB>, height, payload_hash, reserved }` —
  same shape as `MB` with the opaque payload bytes replaced by the
  payload digest. Renames the legacy `transactions_hash` field.
- `MbMeta::last_advanced_eb: HashOf<EB>`.
- `BlockMeta::{last_committed_mb, last_committed_eb}` typed.
- `DBGlobals::{start_block_hash, latest_prepared_eb_hash,
  latest_finalized_mb_hash, latest_computed_mb_hash}` typed.
- `DBConfig::genesis_block_hash: HashOf<EB>`.
- New `pub type EB = SimpleBlockData` alias + `SimpleBlockData::typed_hash()`
  / `eb_hash_of(H256)` for lifting raw Ethereum block hashes into the typed
  envelope.

`HashOf<T>` SCALE-encodes as a bare 32-byte hash (phantom is `#[codec(skip)]`),
so the on-wire/on-disk byte layout is identical to the previous bare
`H256` columns where these fields used to be plain hashes.

Trait sigs in `MbStorageRO/RW` keep `mb_hash: H256` for now — the gain
from threading `HashOf<MB>` through every storage call site (compute,
cli, consensus, processor, etc.) doesn't justify the cascade right now;
typed wrappers at boundary structs already catch the EB-vs-MB confusion
the refactor was about. Call sites pass `field.inner()` where needed.

Fixes #5507
PR #5508 left MbStorageRO/RW and OnChainStorageRO/RW + BlockMetaStorageRO/RW
methods taking raw H256, which forced every caller to thread untyped hashes
and use `.inner()` at boundaries. Type the signatures end-to-end so the
typed values flow through the codebase: EB-block hashes become
`HashOf<EB>`, MB hashes become `HashOf<MB>`. CAS payload hashes
(`set_transactions` return, `transactions(payload_hash)`) stay raw H256
since they're content-addressed, not entity-addressed.

The cascade is real — ~30 files touched across ethexe/common, ethexe/db,
ethexe/compute, ethexe/consensus, ethexe/malachite/service,
ethexe/network, ethexe/observer, ethexe/prometheus, ethexe/rpc and
ethexe/service. Where a function receives raw H256 from an external
source (chain events, malachite-core API, test fixtures) we still cross
the typed boundary with a local `mb_h` / `eb_h` helper rather than
making `HashOf::new` safe, so each conversion remains explicit and
auditable.

`Mirror.processOutgoingAction` flow and existing tests continue to
compile and lint clean across the workspace.
…hash_of/typed_hash

Eliminate the inner()/eb_h() ping-pong introduced when the typed-hash
refactor stopped at trait signatures: now the struct field itself
carries `HashOf<EB>`, so producers, consumers, and DB callers stay
typed end-to-end and only convert at the legitimate boundaries
(alloy event decode, malachite-core wire payload, ABI encoding).

- SimpleBlockData.hash / BlockData.hash → HashOf<EB>
- BlockFullData.hash (mock) → HashOf<EB>
- ChainCommitment.last_advanced_eth_block → HashOf<EB>
- BatchCommitment.block_hash → HashOf<EB>
- CommitmentSubmitted.block_hash → HashOf<EB>
- Transaction::AdvanceTillEthereumBlock.block_hash → HashOf<EB>
- PendingEvent.prerequisite → HashOf<EB>
- ConsensusService::receive_synced_block / receive_prepared_block → HashOf<EB>
- ObserverEvent::BlockSynced → HashOf<EB>
- BlockLoader::load / load_many input/output → HashOf<EB>
- ComputeEvent::BlockPrepared / Event::BlockPrepared → HashOf<EB>
- quarantine::{anchor, verify_passed, is_strict_descendant_of} → HashOf<EB>
- TxValidityChecker.start_block_hash → HashOf<EB>
- consensus::utils::is_eth_block_canonical_to → HashOf<EB>
- Compute error variants (BlockNotSynced, AdvanceMissingHeader, …) → HashOf<EB>

Removed: eb_hash_of(), SimpleBlockData::typed_hash(), and several
per-file `fn eb_h(h: H256) -> HashOf<EB>` helpers that became dead
code now that the source data is already typed. Helpers stay only
where they wrap genuinely untyped input (alloy event decode in
observer, user-supplied reference_block from injected txs, etc.).

EXPECTED_TYPE_INFO_HASH in db.rs updated to match the new layout.

All 12 ethexe-* crates compile (lib + tests). 420/420 nextest-run
tests pass (ethexe-common 16, malachite-core 192, observer/rpc/cli/
network/consensus/prometheus 212).
@grishasobol grishasobol force-pushed the gsobol/ethexe/malachite-typed-block-hashes branch from 16ced2a to 8411f43 Compare May 25, 2026 17:17
@ark0f ark0f mentioned this pull request May 25, 2026
…erator Node fields with HashOf<EB>/<MB>

Cascade typed-hash coverage:

- `BlockHeader.parent_hash`: H256 → HashOf<EB>
- `InjectedTransaction.reference_block`: H256 → HashOf<EB>
- `iterator.rs` Node fields:
    - ChainNode.head / .bottom → HashOf<EB>
    - BlockNode / BlockMetaNode / BlockHeaderNode / BlockEventsNode /
      BlockSyncedNode `.block` → HashOf<EB>
    - MbNode / MbMetaNode / MbProgramStatesNode / MbScheduleNode /
      MbScheduleTasksNode / MbOutcomeNode `.mb_hash` → HashOf<MB>
- `DatabaseIteratorError::NoBlock*` → HashOf<EB>, `::NoMb*` → HashOf<MB>
- `IntegrityVerifier` (visitor + verify_chain + fields): same retype
- Visitor signatures (visit_block_meta / visit_block_synced /
  visit_block_header / visit_mb_schedule_tasks): typed args

Also:
- Drop the iterator `with_hash_eb`/`with_hash_mb` macro branches (the
  storage trait already takes typed hashes, so `with_hash:` covers both).
- Remove the `unsafe { HashOf::<EB>::new(header.parent_hash) }`
  ping-pongs across mempool/quarantine/tx_validity/observer/compute/
  consensus/cli/service.
- Make `HashOf::<T>::zero()` const so it usable in `const` contexts
  (`ProtocolTimelines` test fixture).
- Derive `MaxEncodedLen` on `HashOf<T>`, required by
  `InjectedTransaction#[derive(MaxEncodedLen)]`.

EXPECTED_TYPE_INFO_HASH bumped: 04e137b4… → 26ef9eb1…

The `mb_h(H256) -> HashOf<MB>` helpers stay because malachite-core's
`Block::hash()` returns raw H256 — that's the wire boundary. Per-file
unused `eb_h` helpers in mempool/tx_validity are gated behind
`#[cfg(test)]` since prod paths now consume HashOf<EB> directly.

Tests: 383/383 pass across ethexe-common, ethexe-db, ethexe-malachite,
ethexe-malachite-core, ethexe-network, ethexe-rpc, ethexe-consensus,
ethexe-compute, ethexe-cli, ethexe-observer, ethexe-processor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-friendly Suitable for AI-assisted implementation or review scope: vara.eth Vara Ethereum application layer (L2) type: refactor Internal improvements without changing behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant