Skip to content

feat(state): commit native module state into trie/state_root (fork-gated)#779

Merged
satyakwok merged 2 commits into
mainfrom
feat/native-module-state-root-commitment
Jun 3, 2026
Merged

feat(state): commit native module state into trie/state_root (fork-gated)#779
satyakwok merged 2 commits into
mainfrom
feat/native-module-state-root-commitment

Conversation

@satyakwok
Copy link
Copy Markdown
Collaborator

@satyakwok satyakwok commented Jun 3, 2026

Draft to prevent auto-merge — do not merge; for review only.

Closes the real remaining protocol gap from #776: native-module state (SRC-20 ContractRegistry + NFT NftRegistry) is now committed into the consensus state_root, not just the debug fingerprint. A divergent registry is now rejected by peers instead of relying on deterministic re-execution + the uncommitted blob.

Design (mirrors the proven SIP-6 STATE_IN_TRIE pattern)

  • New fork gate NATIVE_STATE_IN_TRIE_HEIGHT, default u64::MAX on BOTH nets. Deliberately not reusing STATE_IN_TRIE_HEIGHT — it's already active on testnet (6,026,000), so reusing it would retroactively change testnet's state_root and fork the chain.
  • Two fixed trie keys: sentrix/v1/native_src20_registry, sentrix/v1/native_nft_registry (same fixed-key style as total_minted_key/epoch_state_key).
  • Value = registry canonical_hash() (sorted, HashMap-order-independent — landed in feat(state): canonical fingerprint commitment for native module state (SRC-20 + NFT) #776). Always-insert post-fork; empty registry has a stable hash. Captured before the trie mut-borrow (Phase 2f), independent of the SIP-6 gate.

Behaviour

  • Pre-fork: state_root bit-identical to today (native state stays off-trie).
  • Post-fork: any SRC-20 or NFT state change moves state_root.

SRC-20 + NFT, same model

Both registries follow the identical commitment path — not NFT-only.

Fork safety / migration

  • Default-disabled everywhere; activated later via env after soak.
  • Activation requires halt-all + state-root-alignment pre-flight + simul-start so every validator commits identical native state at the activation block (the STATE_IN_TRIE playbook). If validators have pre-existing SRC-20 drift, activation surfaces it as a state_root mismatch (fail-loud) rather than a silent fork — the intended protection.
  • Commitment model: the trie stores the registry canonical hash, not the full registry. Divergence is detected (peers reject the block); recovery is via peer resync (the blob stays the data source). This is a hash-commitment, not full state-in-trie reconstruction.
  • NFT_TOKENOP_HEIGHT stays disabled — the NFT registry commits as empty until it's enabled.

Tests (all green)

native_module_state_root.rs (8): pre-fork preserved · post-fork SRC-20 change moves root · post-fork NFT change moves root · replay-deterministic · different supply differ · different owner differ · deploy-order independent · empty commitment stable. Plus fork_heights gate tests (default-disabled both nets; activates at pinned height).

Did not weaken: NFT no-reuse, max_supply ever-minted, tx.from_address auth, metadata lock, address validation, sentrix-nft internals.

Commands

  • cargo test -p sentrix-nft ✅ (45+2) · cargo test --workspace ✅ (67 suites, 0 fail)
  • cargo fmt --check ✅ · cargo clippy --workspace --all-targets -D warnings

No deploy. No RPC/explorer/wallet/marketplace/bridge/image-bytes. NFT fork not enabled.

Summary by CodeRabbit

Release Notes

  • New Features

    • Native module state (SRC-20 and NFT registries) can now be included in state root calculations when activated via fork height configuration. Currently disabled by default.
  • Tests

    • Added comprehensive test suite validating native module state commitment behavior, including pre/post-fork consistency, determinism, and state root divergence scenarios.

…ted)

Native-module state (SRC-20 ContractRegistry + NFT NftRegistry) was
committed only to the STATE-FP fingerprint (#776), not the consensus
state_root — so a divergent registry was not rejected by peers. Commit
both registries' canonical hashes into the state trie behind a new fork
gate, mirroring the proven SIP-6 STATE_IN_TRIE pattern.

- new gate NATIVE_STATE_IN_TRIE_HEIGHT, default u64::MAX on BOTH nets.
  Deliberately NOT reusing STATE_IN_TRIE_HEIGHT (already active on testnet
  at 6,026,000) — reusing it would retroactively fork testnet's state_root.
- two fixed trie keys: sentrix/v1/native_src20_registry +
  sentrix/v1/native_nft_registry; value = registry canonical_hash (sorted,
  HashMap-order-independent — from #776). Always-insert post-fork (empty
  registry has a stable hash), same semantics as total_minted/epoch.
- update_trie_for_block captures both hashes before the trie mut-borrow
  (Phase 2f), independent of the SIP-6 gate.

Pre-fork: state_root is bit-identical to today (native state stays
off-trie). Post-fork: SRC-20 / NFT state changes move state_root.

Commitment model: the trie stores the registry canonical HASH, not the
full registry — divergence is detected (peers reject the block); recovery
is via peer resync (the blob remains the data source). Activation requires
halt-all + state-root-alignment pre-flight + simul-start so every validator
commits identical native state at the activation block (STATE_IN_TRIE
playbook). NFT_TOKENOP_HEIGHT stays disabled — the NFT registry commits as
empty until it is enabled.

Tests: pre-fork preserved; post-fork SRC-20 + NFT changes move state_root;
replay-deterministic; different supply/owner differ; deploy-order
independent; empty commitment stable; fork-gate default-disabled on both
nets + activates at pinned height.
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@satyakwok satyakwok self-assigned this Jun 3, 2026
codecov/patch on #779 flagged 10 uncovered lines (0%) in
sentrix-trie/src/address.rs: the two new native_*_registry_key builders.
They're exercised by sentrix-core's integration tests, but codecov
measures sentrix-trie in its own package run where its unit tests didn't
call them. Add a unit test asserting both keys are deterministic, mutually
distinct, and distinct from total_minted/epoch/account keys.
@satyakwok satyakwok marked this pull request as ready for review June 3, 2026 19:22
@satyakwok satyakwok merged commit 9fb02d9 into main Jun 3, 2026
20 of 21 checks passed
@satyakwok satyakwok deleted the feat/native-module-state-root-commitment branch June 3, 2026 19:22
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7cab74cb-9ba6-45f0-a863-20f4ac1e20af

📥 Commits

Reviewing files that changed from the base of the PR and between b8346f6 and 87a1c05.

📒 Files selected for processing (5)
  • crates/sentrix-core/src/blockchain.rs
  • crates/sentrix-core/src/blockchain_trie_ops.rs
  • crates/sentrix-core/src/fork_heights.rs
  • crates/sentrix-core/tests/native_module_state_root.rs
  • crates/sentrix-trie/src/address.rs

📝 Walkthrough

Walkthrough

This pull request introduces a new fork-gated feature that commits native-module state (SRC-20 ContractRegistry and NFT NftRegistry) into the account state trie. The implementation establishes fixed registry keys in the trie infrastructure, defines a new fork gate controlled by the NATIVE_STATE_IN_TRIE_HEIGHT environment variable (disabled by default), extends the block-to-trie update pipeline to conditionally capture and write registry hashes when the gate activates, and validates the behavior through a comprehensive test suite covering pre-fork/post-fork equivalence, determinism, state sensitivity, and order independence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sentrix-labs/sentrix#757: Modifies update_trie_for_block to write additional post-fork state-trie entries (similar pattern to native registry commitment but for SIP-6 liveness and total_minted).
  • sentrix-labs/sentrix#661: Prior refactor that extracted trie operations into blockchain_trie_ops.rs, which this PR extends with native state commitment logic.
  • sentrix-labs/sentrix#657: Introduced the fork-height predicate refactor pattern in fork_heights.rs that this PR follows for is_native_state_in_trie_height.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/native-module-state-root-commitment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

github-actions Bot pushed a commit that referenced this pull request Jun 3, 2026
PR #779 merged native-module state-root commitment behind a fork gate
that is off by default everywhere (NATIVE_STATE_IN_TRIE_HEIGHT = u64::MAX
on both nets). Add the operator-side playbook for eventually turning it
on, testnet-first, without splitting the chain.

Covers: pre-flight (same binary/height/tip/state_root + matching SRC-20
and NFT canonical hashes via the existing SENTRIX_STATE_FINGERPRINT tool +
backup), halt-all/simul-start activation with an identical pinned height,
post-activation monitoring, rollback/resync on divergence (unset the gate
= complete deterministic rollback), and the strict sequence: activate +
soak native state-trie first; NFT_TOKENOP_HEIGHT is a separate later
decision; never flip both in one window; no mainnet before a clean
testnet soak.

Docs only — no protocol code, no fork enabled, no tooling added (reuses
the existing fingerprint for cross-node hash comparison).
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