Skip to content

Wire native NFT (SRC-721/1155) apply path before activating NFT_TOKENOP_HEIGHT #773

@satyakwok

Description

@satyakwok

Summary

NFT_TOKENOP_HEIGHT must stay dormant (u64::MAX) until the apply/storage layer ships. The wire format and fork gates are in, but no handler turns a parsed NFT TokenOp into state. Activating the fork now would halt the chain.

Verified state (not assumed — checked against code)

Shipped:

  • Wire format: TokenOp::{DeployNft, MintNft, TransferNft, BurnNft, ApproveNft, SetApprovalForAll} + SRC-1155 variants in crates/sentrix-primitives/src/transaction.rs. Nodes can parse these txs.
  • Three gate sites, all reject pre-fork:
    • crates/sentrix-core/src/block_executor/validate.rs:247 (Pass-1 validate)
    • crates/sentrix-core/src/block_executor.rs:531 (Pass-1 dispatch)
    • crates/sentrix-core/src/block_executor.rs:909 (Pass-2 apply) — also rejects post-fork with "NFT TokenOp dispatch handlers not yet wired (Phase B follow-up PR)".

NOT shipped (the gap):

  • ContractRegistry / SRC20Contract in crates/sentrix-core/src/vm.rs is purely fungible: amount: u64, balance_of, mint/burn/transfer/approve. No token_id, no owner_of, no per-token owner map, no token_type.
  • No NFT storage tables in sentrix-storage.
  • No apply handler functions anywhere.

Why activating now halts the chain

Post-fork the two passes disagree:

Pass-1 (validate): gate opens → NFT tx accepted as VALID
Pass-2 (apply):    still returns Err("handlers not yet wired")
⇒ a valid-looking NFT tx enters the mempool, a proposer includes it in a block,
  every validator then fails to apply that block → block cannot finalize
  → chain STUCK at that height

Note: the validator process does not panic/abort (Audit L3 replaced the old unreachable!() with a graceful InvalidTransaction). The halt is via an unappliable block, not a crash — same operational outcome (chain stops), subtler mechanism.

What "wire the apply path" requires

  • NFT contract storage model — token_id → owner mapping, collection metadata, approvals/operator-approval set. Either a new contract type or an extension to ContractRegistry (currently SRC-20-only).
  • Apply handlers for every variant: DeployNft / MintNft / TransferNft / BurnNft / ApproveNft / SetApprovalForAll and the SRC-1155 batch ops.
  • Remove the post-fork "handlers not yet wired" reject at block_executor.rs:909 once handlers land.
  • Converge Pass-1 ⇔ Pass-2 — both must accept/reject identically post-fork. The current divergence is the halt hazard.
  • RPC read surface for NFT ownership / metadata.
  • Determinism: per-token iteration sorted, no HashMap-order dependence in state_root inputs (same class as the SIP-6 epoch-set fix).
  • Regression tests (fail-before/pass-after) + testnet bake before any NFT_TOKENOP_HEIGHT is pinned.

Activation discipline

Same as every consensus fork on Sentrix: implement → testnet bake → mainnet halt-all + simultaneous-start with NFT_TOKENOP_HEIGHT=<height> on all validators. Do not flip the gate before the apply path is merged and baked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priorityconsensusBFT / PoA / consensus layer

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions