Skip to content

[FEAT] CommitmentRegistry: scope by (chainId, version)#68

Draft
roeezolantz wants to merge 1 commit intomasterfrom
feat/commitment-registry-chain-scoping
Draft

[FEAT] CommitmentRegistry: scope by (chainId, version)#68
roeezolantz wants to merge 1 commit intomasterfrom
feat/commitment-registry-chain-scoping

Conversation

@roeezolantz
Copy link
Copy Markdown
Contributor

Summary

Stores FHE computation commitments by (chainId, version, handle) instead of (version, handle). Same handle bytes posted from different source chains are now independent commitments — eliminates cross-chain shadowing/collision when TN later looks up commitment integrity.

versionStatus is also now per (chainId, version). Chains have independent crypto-material lifecycles; one chain rotating keys says nothing about another. Multiple Active versions per chain are allowed (rotation overlap window).

This is a fresh deploy of the v2 contract, not an upgrade of the existing one. The old contract's data was disposable and is left in place as orphaned storage.

API changes (breaking)

  • postCommitments(uint64 chainId, bytes32 version, bytes32[] handles, bytes32[] commitHashes) — chainId is now first, uint64.
  • postCommitmentsSafe(...) — same shape.
  • setVersionStatus(uint64 chainId, bytes32 version, VersionStatus newStatus) — per-chain lifecycle.
  • All view fns gain chainId as first arg: getCommitment, getSize, getHandleByIndex, getHandles, getVersionStatus.

Events

  • CommitmentsPosted(uint64 indexed chainId, bytes32 indexed version, uint256 batchSize)
  • CommitmentsPostedSafe(uint64 indexed chainId, bytes32 indexed version, uint256 newlyPosted, uint256 skipped)
  • CommitmentMismatchSkipped(uint64 indexed chainId, bytes32 indexed version, bytes32 indexed handle, bytes32 stored, bytes32 attempted) — new; surfaces silent commitment drift in postCommitmentsSafe when a re-post has a different commitHash than what was stored. Strictly-equal redeliveries stay silent.
  • VersionStatusChanged(uint64 indexed chainId, bytes32 indexed version, VersionStatus oldStatus, VersionStatus newStatus)

Errors

  • InvalidChainIdchainId == 0 rejected at every entry point as defense-in-depth.
  • VersionNotActive(uint64 chainId, bytes32 version), CommitmentAlreadyExists(uint64 chainId, bytes32 version, bytes32 handle), InvalidVersionTransition(uint64, bytes32, …) gain chainId.

Deploy script

scripts/deploy.ts now takes a CHAIN_IDS env var (comma-separated) and pre-activates INITIAL_VERSION (0x…02 to match fhe-engine's bumped COMMITMENT_VERSION) on each chain. Default for local devnet is 412346.

Tests

CommitmentRegistry.behavior.ts — 99 tests passing. Net additions over the v1 suite:

  • 6 tests for cross-chain isolation (same handle on different chains is independent; getSize/getHandles don't leak; chainId == 0 rejected; chain B duplicate doesn't revert chain A's prior commitment).
  • 3 tests for chainId == 0 rejection at each entry point (postCommitments, postCommitmentsSafe, setVersionStatus).
  • 2 tests for CommitmentMismatchSkipped (emit on disagreement; stay silent on identical redelivery).
  • Per-chain version lifecycle test (CHAIN_A's V1 deprecation doesn't touch CHAIN_B's V1).
  • Multi-Active-per-chain rotation test.

Gas costs unchanged from v1: ~47K per commitment at scale.

Test plan

  • pnpm compile clean
  • pnpm test — 99 passing
  • npx hardhat run scripts/estimateGasArbitrum.ts --network arbitrumSepolia (cosmetic — gas changed from v1 by <1%)

Companion PR

This is paired with the outer-repo PR that bumps the submodule pointer + updates the blockchain-poster + fhe-engine. That PR depends on this one landing first.

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