Skip to content

[Language design] Model typed cross-Script transaction roles without runtime linkage #10

Description

@a19q3

Summary

Design a CKB-native source and metadata model for typed transaction roles across independently compiled Scripts.

The goal is to let one CellScript entry declare the foreign inputs, outputs, dependencies, and peer Script identities that it relies on in the same atomic CKB transaction—without adding an ELF linker, runtime calls, or a shared hidden state model.

This work should begin only after the artifact-only composition boundary in #9 is specified well enough to expose real role and conflict requirements.

Problem

CellScript can already:

  • inspect transaction and Script Group views through typed SourceView;
  • construct and compare Script/ScriptRef values;
  • import schemas and pure helpers at compile time;
  • bind package interfaces and deployment identities;
  • express explicit local input/output transitions.

What it cannot express as one typed protocol contract is:

“This action is valid only when a foreign Script consumes these typed inputs, creates these typed outputs, and independently accepts the same transaction under this exact or compatible identity.”

Applications can hand-code individual syscall checks, but the relationship is not a first-class role graph. It is therefore missing from interface compatibility, builder generation, ProofPlan, audit output, and protocol-level transaction composition.

Argent's closed/open ICC and consumes/emits/observes model demonstrate the product value of making the application graph source-level. CellScript must adapt the idea to CKB's Cell Model and Script Groups rather than copying Kaspa covenant semantics.

CKB-native model

CKB already executes independent Lock and Type Script Groups against the same transaction. The language feature should describe and verify relationships between those groups; it should not call one Script from another.

flowchart TB
    SRC["CellScript protocol/role declarations"] --> A["Compile artifact A obligations"]
    SRC --> B["Compile artifact B obligations"]
    SRC --> PB["Emit ProtocolBundle role graph"]

    TX["One atomic CKB transaction"] --> GA["Script Group A"]
    TX --> GB["Script Group B"]

    GA --> VA["Artifact A validates its observable facts"]
    GB --> VB["Artifact B validates its observable facts"]

    VA --> OK{"Both independently accept?"}
    VB --> OK
    OK -- "yes" --> ACCEPT["Transaction valid"]
    OK -- "no" --> REJECT["Transaction rejected"]
Loading

Required role classes

The design should separate these concepts rather than overloading ordinary action parameters:

Local lifecycle roles

  • inputs controlled by the current Script Group;
  • outputs created or updated under the current Script identity;
  • existing consume, create, transition, and bounded lifecycle rules.

Closed foreign roles

A peer role bound to:

  • exact package/interface hash;
  • exact serialized state schema;
  • exact deployment and Script identity policy;
  • fixed Lock/Type role;
  • explicit transaction or group source;
  • fixed or bounded cardinality.

This is the CKB analogue of a statically linked peer application, but it remains an independently executed Script.

Open foreign roles

A peer role whose implementation is chosen at transaction construction time, subject to an explicit interface/schema/effect contract and an on-chain-verifiable Script identity binding.

Open roles must not rely on a Registry lookup as consensus proof. See the separate interface-bound Script-handle issue that will build on this role model.

Dependency roles

  • code or data CellDeps;
  • HeaderDeps;
  • spawned VM/IPC verifier contracts;
  • read-only configuration Cells.

Dependency roles remain distinct from consumed inputs and created outputs.

Possible source shape

This issue must not preselect final syntax. A strawman only illustrates the semantic information:

protocol Settlement {
    closed input order_before: OrderState
        from transaction
        script order_v1

    open input asset_before: FungibleAsset
        interface fungible_v1

    output order_after: OrderState
        verified_by order_v1

    output asset_after: FungibleAsset
        same_implementation_as asset_before
}

action settle(...) for Settlement {
    transition order_before -> order_after

    verification
        require asset_after.amount == asset_before.amount
}

The accepted design may use a manifest rather than new language syntax. The non-negotiable part is the typed role graph and its evidence, not the spelling.

Role graph and obligations

graph LR
    ENTRY["Current entry"] --> LI["Local input role"]
    ENTRY --> LO["Local output role"]
    ENTRY --> FI["Foreign input role"]
    ENTRY --> FO["Foreign output role"]
    ENTRY --> DEP["CellDep/HeaderDep role"]

    FI --> ID["Script/interface identity"]
    FI --> SCHEMA["Typed schema decode"]
    FO --> CORR["Output correspondence"]
    FO --> PEER["Peer independently executes"]
    DEP --> POLICY["Read-only identity policy"]
Loading

For each role, metadata must record:

  • stable role identity and source span;
  • local/foreign/dependency classification;
  • transaction versus group-relative source;
  • cardinality;
  • Lock/Type/CellDep role;
  • Script and deployment identity policy;
  • interface and schema requirements;
  • readable fields and required relations;
  • whether the current Script checks the fact on chain;
  • which peer artifact independently enforces its own transition;
  • builder assumptions that remain off chain.

Soundness rules

  1. Presence is not authorization. Observing a peer input proves only that it is present and matches the declared identity.
  2. Shape is not behavior. Decoding a peer state does not prove that the peer intended the observer's transition.
  3. Builder construction is not consensus proof. Every claimed on-chain fact needs generated verifier coverage.
  4. Peer success is independent. The bundle must execute each participating Script Group; one Script cannot claim another has accepted without evidence.
  5. Closed and open roles cannot collapse. An exact implementation dependency must not silently become an open interface slot.
  6. Transaction-wide sources are explicit. A role must not accidentally widen from Script Group to the complete transaction.
  7. Cardinality is executable. A bound in metadata is insufficient without runtime count enforcement.
  8. Interface identity must be bound. Package/Registry metadata alone cannot identify the Script bytes executing on chain.

Implementation phases

Phase 0 — use cases and threat model

Select at least three concrete multi-Script protocols, for example:

  • token/order atomic settlement;
  • factory/child Type ID launch;
  • DAO proposal plus authorization Lock;
  • shared pool plus independent token Type Scripts.

For each, document current manual checks and the intended role graph.

Phase 1 — metadata-only role graph

This phase must not advertise on-chain coverage.

Phase 2 — closed roles

  • bind exact peer artifacts, interfaces, schemas, deployments, and Scripts;
  • generate current-Script observation checks;
  • construct and dry-run all peer Script Groups through ProtocolBundle;
  • add negative fixtures for identity, source, cardinality, schema, and output mismatches.

Phase 3 — open roles

  • add only after the interface-bound Script handle has a complete consensus binding;
  • preserve exact runtime-selected implementation across declared continuations;
  • ensure both observer and peer independently validate the transaction;
  • add substitution, downgrade, and Registry-spoofing adversarial tests.

Acceptance criteria

  • An accepted RFC defines local, closed foreign, open foreign, and dependency roles.
  • At least three real protocol fixtures justify the model.
  • Roles are canonical metadata and public-interface entries.
  • Every claimed check maps to typed semantics, ProofPlan, lowering, and machine evidence.
  • ProtocolBundle builds and dry-runs every participating Script Group against identical transaction bytes.
  • Closed roles bind exact interface, deployment, and Script identities.
  • Open roles cannot ship before an on-chain-verifiable interface-handle contract exists.
  • Transaction versus Script Group scope is explicit and tested.
  • Fixed and bounded cardinality rules are executable.
  • Negative tests cover missing, extra, reordered, substituted, incompatible, and non-executed peer roles.
  • Generated builder, CLI, LSP, VS Code, Registry, checker, and docs agree.
  • No ELF-linker or cross-Script-call claim is introduced.

Non-goals

  • synchronous contract calls;
  • shared mutable VM memory;
  • compiling several Scripts into one ELF;
  • Kaspa covenant IDs or P2SH template receipts;
  • trusting Registry availability during consensus execution;
  • inferring peer behavior from matching state shape;
  • adding actor/mailbox terminology to CellScript;
  • hiding transaction roles behind ordinary generic values.

Dependencies

References

Activity

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

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions