Skip to content

[Language/ABI] Support policy-constrained Script instances in compatible-open handles #80

Closed

Description

@a19q3

Objective and status

Extend the existing ScriptHandle<I> and VerifierHandle<I> admission model with a separate, versioned policy for constrained Script instances. Permit explicitly bounded argument values under independently checked, on-chain-enforced constraints while retaining the concrete identity and authorisation of every selected instance.

Status: bounded technical implementation completed on the 0.32 branch. #28 and #29 remain completed foundations. Implementation owner: Codex under the maintainer’s 2026-10-17 request. An issue-specific author self-review is recorded; no independent human audit was performed and no earlier waiver is inherited. The linked closure evidence identifies the signed implementation, full gate provenance and retained artifacts. This is not a release or public deployment approval.

Existing boundary and motivation

#28's member encoding commits to the complete Script hash, including concrete args. Both its exact and compatible implementation-selection modes retain that binding. The existing format has no wildcard or schema-only args policy, and #11's exact-handle format remains unchanged.

A consumer may need to admit independently configured instances of approved code without enumerating every concrete argument combination in its immutable member set. This issue owns that general admission contract. Shared code and an accepted argument schema alone must never make two instances interchangeable or grant authority over their Cells.

Before choosing compiler changes, demonstrate a minimal limitation of the existing exact-instance path, identify the smallest owning layer, and include a non-financial constrained-instance use case under #43's general-capability admission rule. A fixed verifier allowlist is a required regression/control example; by itself it does not demonstrate a need for variable instances.

Required design contract

  1. Separate two policy dimensions. Preserve [0.32][Language/ABI] Stabilize generic compatible-open Script and verifier handles #28's exact-versus-compatible implementation selection. Define exact-instance versus constrained-instance admission separately, enumerate the supported combinations, and reject unsupported combinations. Freeze new schema identifiers, canonical encoding, domain-separated commitments and migration rules without reinterpreting old bytes or weakening old readers.

  2. Bind implementation and instance evidence. Retain the approved executable bytes, independently recomputed interface receipt, Script role, code hash/hash type, actual code CellDep/OutPoint, target/profile/ABI, deployment and network context. Bind the argument schema, constraints, policy version and policy identity. The selected concrete Script, including its actual args, remains identified in the final admission and transaction records. Define any separation between reusable implementation evidence and per-instance evidence explicitly.

  3. Authenticate constraints and decode actual args. Specify which fields may vary, allowed values or relations, exact source/index scope, canonical encoding, and byte/count/decoding limits. Begin with bounded fixed-layout argument values unless a demonstrated case requires more. Validate the actual transaction Script args against the authenticated policy in CKB-VM. A witness or Registry record cannot authorise its own expected root, owner or constraints.

  4. Specify root and configuration placement. The current [0.32][ProtocolBundle] Stabilize runtime-selected open cross-Script roles #29 native admission path requires the consumer's entire Script args to equal the 32-byte policy root. If the new profile combines that root with instance configuration, define a versioned layout and independently checked root/field accessors. Keep consumer root storage distinct from the selected participant's argument policy, and preserve the existing 32-byte-root path.

  5. Preserve instance authority. A permitted argument value establishes only the claim defined by its policy. Owner identity, spending authority, genesis/uniqueness, lifecycle rules and cross-Cell correspondence require explicit enforcing predicates. An instance admitted under the same code and policy cannot replace another instance in an operation that authorises a particular pool, owner, recipient or state lineage. Foreign observation never grants local consume/create authority.

  6. Define evolution and downgrade rules. Preserve immutable-snapshot, active/yanked and admission-floor semantics. Specify constraint/schema changes, policy widening, stale policies and cross-mode downgrade rejection. Root replacement or live revocation requires an explicitly authenticated transition contract; a later Registry edit cannot change an immutable root. Type-hash selection retains exact current code/OutPoint and checked history bindings. Compatibility, package updates and policy/deployment authorisation remain separate, consistent with [Toolchain][Upgrade] Add a transactional package, interface, and deployment upgrade plan #20.

  7. Keep verifier inputs explicit. The accepted [0.32][Language/ABI] Stabilize generic compatible-open Script and verifier handles #28/[0.32][ProtocolBundle] Stabilize runtime-selected open cross-Script roles #29 spawned-verifier profile is parameterless and inherits its consumer's Script/group context. Distinguish Script args from child argv, IPC requests and proof/public-input codecs. Preserve selected dependency binding, actual SPAWN/WAIT execution and child-failure propagation. This issue does not implicitly add arbitrary verifier argv, hook callbacks or broaden the exact ZK profiles in [Language/Verifier][Research] Add typed zero-knowledge verifier contracts without a circuit DSL #22/[0.32][ZK/P2] Bind bounded multi-Cell transitions to complete protected state sets #44/[0.32][ZK/P3] Track circuit, key and verifier changes with authorized migration evidence #45; any required extension needs an explicit bounded contract and acceptance evidence.

  8. Compose with ProtocolBundle. Support existing exact-instance and new constrained-instance admission through [0.32][ProtocolBundle] Stabilize runtime-selected open cross-Script roles #29's existing materialization and generated-builder paths. Bind the concrete participant, role, source/index, schema, cardinality, dependency, witness and instance policy to the complete transaction before signing. Preserve claim attribution to current-Script checks, required peer groups, bundle dry-run and consensus. Interface compatibility or successful membership does not establish peer acceptance or behavioral equivalence.

Acceptance criteria

  • A versioned design and threat model fixes supported policy combinations, authority sources, canonical codecs, error behavior and numeric resource limits. Unsupported shapes fail closed.
  • Existing [Language/ABI] Bind runtime Script values to verified package interfaces #11 exact handles and [0.32][Language/ABI] Stabilize generic compatible-open Script and verifier handles #28 exact-member encodings, roots, selections and verification retain their semantics, with frozen regression vectors. Old-format inputs cannot be reinterpreted as constrained admission.
  • The independent checker verifies the new receipt/policy bindings and advertised machine enforcement. Rebound-hash mutations remove or alter args decoding, bounds, root access, constraint checks, identity binding and rejection paths and are rejected.
  • CKB-VM cases cover valid, empty where admitted, maximum and over-limit args; malformed/noncanonical encodings; unauthorised owners; wrong role/source/network/code/CellDep/deployment; stale policies; policy widening/downgrade; and cross-mode proof substitution.
  • A fixed verifier allowlist continues to work. Missing/wrong children and failing child predicates reject through actual execution; admitting a verifier is not counted as executing it.
  • Two independently configured pools share the same deployed implementation while retaining distinct complete instance identities. Both work independently and concurrently without spending a universal coordinator Cell. Under [DeFi][FIN-11] Canonical pool identity, permissionless creation and reusable state layout #61/[DeFi][FIN-02][M1] Enforce authentic pool custody, asset identity and LP supply #52, demonstrate authentic genesis, configuration, custody and complete required Script groups.
  • Both pool A and pool B satisfy the admission policy, yet substituting B's state, reserves, owner or identity into an operation authorised for A rejects at the intended enforcing Script. Also test missing peers and a selected peer that rejects despite valid admission. Negatives use otherwise-valid signatures and correctly constructed unrelated groups so they exercise the intended boundary.
  • Native admission, CLI, generated builders and SDK/adapter materialization agree on canonical policy/witness and final transaction bytes. Reject post-check, post-build and post-signing substitutions. Signed-intent/retry integrations retain their separately defined authority boundaries, including [DeFi][FIN-26] Scoped signed intents, delegation, nonces and replay protection #76 where used.
  • Source/type checking, lowering, ProofPlan, metadata, independent checker, diagnostics, formatter/LSP/editor, WASM metadata and documentation agree wherever affected. Publish valid and late-invalid cycles, stack/memory, ELF, witness/transaction-byte and capacity budgets at frozen maxima.
  • Retain identified source/compiler/checker/artifact/CellDep/transaction evidence and independent reference vectors. Run focused checks and the applicable unified dev, backend and ci gates before technical acceptance; ordinary commits use commit plus focused checks. Node, public deployment, external audit and release claims remain separate.

Dependencies and related work

Issue(s) Relationship
#11, #28, #29 Completed foundations and mandatory compatibility constraints for this extension.
#61, #52 Application validation for reusable pool instances and authentic custody. #80 does not complete pool identity, custody or financial accounting. Do not create a circular hard dependency: general policy work can use small independent fixtures; full pool evidence consumes the relevant application contracts.
#43, #54, #55, #60 Protocol/application scope and reproduction remain separate. Existing exact-deployment finance paths do not automatically depend on #80. Promote a dependency only for a demonstrated, explicitly scoped need.
#47, #48, #49 Conditional composition only. Variable argument values do not inherently require allocation, nested dynamic codecs or heterogeneous Cell selection. Use their contracts if the chosen profile needs those capabilities.
#69, #71, #78 Optional future hook/extension consumers. Preserve exact operation/pool/permission binding and actual execution; no callback or financial-delta semantics are granted by a handle.
#20, #25, #76 Preserve the separation of compatibility, upgrade authority, cryptographic authority and exact transaction/intent authorisation.
#22, #44, #45 Existing exact ZK statement, verifier/key, state-binding and migration contracts remain intact.

These links describe design and validation relationships, not native GitHub blocking relationships or release commitments. Pool keys, fee policies, custody and hook business rules remain application-owned; no finance-specific parser, IR or codegen behavior is introduced.

Activity

  1. changed the title [-][Post-0.32][Language/ABI] Support policy-constrained Script instances in compatible-open handles[/-] [+][Language/ABI] Support policy-constrained Script instances in compatible-open handles[/+] on Oct 18, 2026
  2. a19q3 commented on Oct 18, 2026

    @a19q3
    CollaboratorAuthor

    Completed the bounded implementation and technical acceptance on 0.32.

    • Implementation: dd58ff19. The clean signed runtime acceptance snapshot is f55508b5.
    • Final profile, evidence archive and hashes: profile, acceptance inventory and archive, final signed commit.
    • All four implementation/instance policy combinations are supported for Lock/Type participants. New 848-byte policy, 1768-byte selection and 208-byte consumer configuration remain separate from the old 202-byte exact and 656-byte open formats. Constrained spawned-verifier inputs fail closed; the existing parameterless verifier profile still executes actual SPAWN/WAIT and propagates child rejection.
    • Independent checker coverage includes fourteen external CCC/Molecule vectors and more than 200 rebound-machine mutations. Native/CLI/generated TypeScript/SDK parity binds final signed transaction bytes and rejects post-check/build/sign substitutions.
    • O0–O3 application coverage retains sixteen document cases and nineteen two-pool cases per optimization level. Authentic issuance, genesis, custody, required groups, independent/concurrent pool swaps and policy-valid A/B substitutions execute in CKB-VM. Retained pool transactions replay in a fresh context without recompiling or resigning. The broader financial scope of [DeFi][FIN-02][M1] Enforce authentic pool custody, asset identity and LP supply #52/[DeFi][FIN-11] Canonical pool identity, permissionless creation and reusable state layout #61 remains separate.
    • Eighty-eight resource observations cover combined maximum bounds and late failures, with full traces, transaction bytes, source/artifact/dependency identities and capacity checks retained. These are named fixture observations, not a universal worst-case proof.
    • Full dev, ci and backend gates passed. The evidence records the CI test-only source delta and supplemental regression, and the final backend includes that regression on clean signed f55508b5. Two earlier backend attempts remain failures in the archive: concurrent executable fixtures and a shared CKB checkout that moved away from its pin. The successful replay uses serial tests and the exact clean pinned CKB revision. A subsequent gate-only serialization fix and final evidence/docs are validated by the ordinary commit gate.

    Implementation ownership and issue-specific author self-review are recorded in the profile. No independent human audit or inherited waiver is claimed. SSRI/IPC, new verifier argv, release publication and public deployment are outside this acceptance.

  3. a19q3 commented on Oct 28, 2026

    @a19q3
    CollaboratorAuthor

    Follow-up on the 32-member candidate limit: it is a reasonable bound for the current profile, but the existing boundary tests establish correctness at 32 members, not that 32 is sufficient for every application.

    The distinction relevant to #80 is:

    • The limit applies to the candidates in one authorization-set snapshot. A transaction selects the member it needs; it does not have to execute every candidate.
    • In the original exact-instance model, each member commits to a complete Script, including concrete args. Enumerating every user or pool configuration would therefore consume separate slots and quickly exhaust a small catalog.
    • [Language/ABI] Support policy-constrained Script instances in compatible-open handles #80's separate constrained-instance policy addresses that problem for Lock/Type participants: multiple configurations can use the same selected implementation under explicit args constraints. Each concrete instance must still be identified, checked against the actual transaction, and protected against substitution by another independently policy-valid instance.

    The number 32 is an engineering choice, rather than an inherent Merkle-proof requirement. Keeping the other open-selection fields unchanged gives:

    Candidate capacity Merkle depth Open-selection bytes
    32 (current) 5 656
    64 (hypothetical) 6 688
    128 (hypothetical) 7 720

    The larger sizes are layout calculations only, not implemented profiles or measured VM costs. They refer to the original open-selection record embedded in #80's larger envelope. Each additional level adds one sibling hash and one path-hashing step; checking all candidates during native admission also has a separate cost.

    Suggested follow-up:

    1. Document 32 as the current, versioned per-set bound and distinguish implementation diversity from instance/configuration diversity.
    2. Evaluate representative applications before treating that number as a permanent design limit. Use constrained instances when configurations cause the growth; evaluate a larger set when genuinely distinct implementations or admitted versions exceed 32.
    3. Any expansion should version the affected wire formats, preserve old roots/readers, update compiler/checker/builder contracts, and measure maximum and late-rejection cases. Changing an application's authorized root still requires its explicit authorization mechanism.

    The accepted profile remains unchanged. This records a future sizing and evolution question alongside the existing constrained-instance contract.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions