Repository navigation
[Design][SSRI] Script self-description, contextual queries, and transaction construction for wallets and SDKs #82
Description
User problem
Status: design proposal, not an announcement that CellScript already supports SSRI. A wallet or SDK developer encountering CellScript for the first time should be able to determine what a deployed Script offers, how a particular instance is configured, and how to construct a candidate transaction without first understanding compiler-internal metadata.
This issue designs an SSRI-compatible entry point and its boundary with the existing builder. The overall decision is tracked under Design workstreams below; it may result in implementation, a narrower scope, or deferral. SSRI need not become the sole entry point.
Build on existing mechanisms rather than reinventing trust
CellScript already has compiled ELF artefacts, typed interfaces, an independent checker, and ProtocolBundle for coordinating multi-contract transactions. #28/#29 check permitted implementations and participating roles; #80 additionally checks full Script args and concrete instances. These answer who may participate. The proposed SSRI entry point answers how tooling can discover and use them.
For example, an issuer may legitimately issue a credential of category 6 while an observer policy accepts only categories 1–5. SSRI may correctly report category 6, but that must not cause the observer to accept it. Discovery and admission remain separate steps.
Primary sources and observed discrepancies
- The original SSRI design describes method paths, Code/Script/Cell/Transaction environments, and off-chain Script execution.
- Pinned
ckb-ssri-std@ 93f3a779. The method macro uses short method hashes and hex argv; the fallback distinguishes empty argv from a special off-chain VM version. - The original design and this library describe the off-chain query syscall numbering differently. The README still contains TODOs for a unified entry point and attribute macros. Reviewers must establish the target server, client, fork/tag/commit, and actual golden vectors rather than synthesising an imaginary “latest SSRI”.
- The original design lists
get_cell_deps, whereas the inspectedssri_methods!dispatch table only includes version/get_methods/has_methods. Any compatibility claim must enumerate supported methods rather than imply complete compatibility.
These are source-code observations; no SSRI server interoperability test has yet been performed.
Proposed first use cases and candidate scope
Start with non-financial credentials to avoid mixing asset economics into a generic entry point:
- Query version and methods using a pinned code OutPoint/data hash; report the exact supported scope.
- Query a concrete instance using a complete Script, reporting namespace, category, and serial number. A Code environment containing only a code hash must not be treated as a particular instance.
- Return a candidate revocation transaction against a pinned transaction snapshot, then pass it through existing admission, live resolution, wallet signing, and full Script-group verification.
The first two can be investigated independently. The third depends on the overall decision and the candidate-transaction boundary. Do not add method names or return types to stable CellScript syntax before review. Do not force the generic SSRI UDT trait onto credentials; declare a custom namespace separately.
sequenceDiagram
autonumber
participant W as Wallet / SDK
participant S as SSRI executor
participant E as Pinned code and context
participant B as CellScript admission / Builder
participant C as CKB verification
W->>S: Query methods and instance details
S->>E: Execute in pinned environment
E-->>W: Information + provenance (not transaction authorisation)
W->>S: Request candidate transaction
S-->>W: Candidate inputs / outputs / witnesses
W->>B: Full candidate + user intent
B->>B: Recheck implementation, instance, live Cells and limits
B-->>W: Exact bytes to sign
W->>C: Complete signed transaction
C-->>W: Results of all required Script groups
Compare all three integration placements
| Placement | Hypothesised benefit | Questions to resolve |
|---|---|---|
| Add an SSRI entry point to the same ELF | Query and verification logic are bound most directly | Does dispatch change ordinary verification? How are code size, checker coverage, and special syscalls isolated? |
| Separate companion ELF bound to the main ELF and interface | Isolates the query execution environment | This does not automatically mean “methods provided by the main Script itself”. Will existing SSRI consumers recognise it? How is a stale companion rejected? |
| Off-chain adapter using existing metadata/builder | Easiest to experiment with and reuse | If no Script method is actually executed, this is an adapter, not Script-sourced semantics or a trust-free service |
Selection criteria: interoperability with actual consumers, verifiability of identity, behaviour under mismatched upgrades, binary size and runtime budgets, and maintainable complexity. No option is preselected.
Context and result contract
Each method must declare its minimum environment and what it reads. A Code method cannot conjure an instance; a Script method must bind the full code_hash/hash_type/args; a Cell method must bind an OutPoint and snapshot; a Transaction method must bind the complete transaction, input snapshot, network, and required dependencies. Methods requiring live chain queries must additionally specify query results and the observed tip. Identical code need not produce identical results across different chain states.
Result provenance should record at least the executing code hash/OutPoint, interface and method versions, complete context hash, request/response hashes, executor version, and consumed budget. Such records support source verification; a JSON field alone cannot establish authenticity or grant spending authority. The caller must verify the identity or independently replay the execution.
Cache keys must include code, instance, method, arguments, context, and chain snapshot. Invalidate on Type ID changes, consumed Cells, reorganisations, or input-snapshot changes. Do not cache information for all instances solely by code hash. Returned transactions must still be checked against the original signing intent, including amounts, recipients, fees, and capacity. The SSRI server must not hold private keys.
Encoding, error, and budget checklist
- Specify the method-path algorithm, byte order, hex/raw-byte argv boundary, missing/extra argument behaviour, Molecule schema, null values, and trailing-byte rules.
- A short method ID does not uniquely authenticate a complete signature. Detect collisions at publication; never silently change parameters or semantics under the same ID across versions.
- Distinguish unsupported method, insufficient context, malformed input, budget exceeded, stale snapshot, business-rule rejection, and unavailable host. An unknown method must not fall back to successful verification.
- Reconcile the SSRI
limit=0“return all” convention with total host budgets: an internal hard limit still applies. Exceeding it must fail explicitly or use a versioned pagination strategy; never silently truncate and claim completeness. - Before testing, specify ceilings for method count, argument/response bytes, context reads/queries, VM cycles, host time, and memory. Numeric values await review and measurement; they are not implemented guarantees.
- Off-chain extension syscalls must not enter ordinary on-chain verification. The same-ELF option particularly needs evidence that dispatch cannot bypass the original verifier.
Incremental implementation and validation
- Pin a reference server/client/source revision and minimal external consumer scenario with SSRI maintainers; retain byte-level vectors.
- Write an independent native Rust reference contract for equivalent discovery/instance queries, using the same context and budgets as the baseline.
- Run minimal experiments for all three placements; record whether an unmodified reference client can invoke each. Name every incompatibility.
- Only after selection, design the CellScript generator/adapter and source→interface→builder mapping. Preserve existing CLI/ABI semantics and version extensions explicitly.
- Introduce the candidate-transaction flow with pre-signing wallet checks; any byte or live-snapshot change requires fresh admission and signing.
- Freeze the accepted boundary, provide a tutorial, offline reproductions, and review conclusions, then open explicitly scoped implementation deliverables.
| Adversarial case | Required behaviour |
|---|---|
| Same code, different args; cache returns details of another instance | Reject provenance mismatch; do not reuse instance cache |
| Query succeeds but credential Type rejects revocation | Whole transaction fails; do not promote a query result to consensus authority |
| Cell/Transaction method requested with only Code context | Explicit insufficient-context error |
| New Type-ID code or previously spent input | Invalidate and rebuild/revalidate |
| Huge pagination, malformed offset/argv, oversized return | Bounded rejection before allocation/decoding or at the relevant boundary |
| Forged server response/provenance | Local verification/replay fails; result cannot authorise anything directly |
| Candidate transaction changes recipient or raises fees | User-intent check fails; no automatic signing |
| Ordinary on-chain entry receives a special SSRI call | Reject unauthorised path; original verifier remains unavoidable |
Authoring direction — 2026-10-19
Apply the authoring requirements in #47/#48/#49 to the proposed discovery and construction interface. Review a declaration of named methods, typed parameters/results, required context, and named resource limits before freezing any public syntax. Derive discovery descriptions and client/builder bindings from one canonical interface contract where supported, rather than making authors repeat method signatures, positional limits, or compiler-internal view types at each call. Record every mapping that cannot preserve the selected SSRI protocol's semantics; generated convenience does not establish wire compatibility.
Keep code, concrete Script instance, Cell snapshot, and transaction context distinguishable in author-written examples. A convenient context object must not silently substitute code identity for full instance identity, choose a chain snapshot, or grant signing authority. Use structurally resolved fields and policies rather than encoding ordinary field references in opaque policy strings. Candidate construction must still expose user intent and pass the existing admission and signing checks.
For query/codec helpers, prefer direct reads when no view needs to be retained; use an explicit borrow scope only when its lifetime is meaningful. Target bounded non-escaping helper composition without promising it is already supported. A host response is bounded typed data with provenance to verify, not a borrowed on-chain Cell view or an owned resource. Nested results require their declared #48 codec and bounds; an off-chain SDK's allocation does not imply #47 on-chain heap support.
Before stable API review, show a complete discovery → instance query → candidate transaction example, including author declarations, generated consumer calls, reusable helpers, and malformed/stale-context rejection. Clearly label proposed syntax and unsupported cases. Evaluate the same author-facing workflow for all three placements; a same-ELF, companion, or adapter choice must not itself dictate the public spelling.
Relationship to existing issues
#28/#29/#80 continue to own admission. #47/#48/#49 are neither reopened nor deemed completed by this design. Fixed-size queries do not require a generic allocator. Nested dynamic on-chain results require the specific codec scope of #48; an off-chain host handling dynamic data does not imply corresponding on-chain CellScript support. Cell-collection transfers remain within #49, while owned dynamic collections are relevant to #47.
Closure criteria and questions for reviewers
- Review the complete discovery/instance/construction workflow against the [0.33][Runtime] Add bounded allocation-backed value collections and deterministic Map/Set #47/[0.33][ABI] Support bounded nested dynamic values with canonical codecs #48/[0.33][Runtime] Extend bounded Cell selection and correspondence for heterogeneous and dynamic data #49 authoring direction, including generated-client parity, named context and limits, helper lifetime boundaries, and explicit unsupported cases before stable API freeze.
- Chosen placement and trade-offs of rejected alternatives are explicit; external interoperability targets are pinned to exact versions.
- Per-method context, authorisation, encoding, error, budget, and caching rules are frozen.
- At least one independent-client interoperability experiment is documented; unimplemented candidate-transaction capabilities are clearly labelled.
- Adversarial cases above have test plans and assigned responsibilities; no privilege expansion in ordinary verification.
- The maintainer identifies implementation owners and records review dispositions; design closure is separate from implementation acceptance.
Hanssen, Retric, Guopeng, and other reviewers: which SSRI methods should come first? Can a companion ELF meet the expected semantics? Which specification or implementation governs current discrepancies? Which off-chain context information requires provenance or replay? If we only build an adapter, how should it be named to avoid misleading users? Mentioning reviewers here does not imply that they have reviewed or endorsed the proposal.
Design workstreams
Overall decision: #81. On-chain communication and lifecycle: #83. This issue is #82; it may undertake discovery/context experiments without waiting for general-purpose on-chain IPC.
Activity
[-][Design][SSRI] 面向钱包与 SDK 的 Script 自描述、上下文查询和交易构造入口[/-][+][Design][SSRI] Script self-description, contextual queries, and transaction construction for wallets and SDKs[/+]a19q3 commentedon Oct 18, 2026
考虑到本议题涉及的主要开发者和评审者中有不少以中文交流,为方便大家阅读与讨论,也出于对不同语言使用习惯的尊重,特在此附上中文版。英文正文仍作为当前 issue 的主要描述;以下中文内容供对照参考。
面向钱包与 SDK 的 Script 自描述、上下文查询和交易构造入口
状态:设计提案,不是“CellScript 已支持 SSRI”的公告。 对初次接触 CellScript 的钱包/SDK 开发者,希望能够回答:部署的 Script 提供什么功能?当前实例如何配置?如何构造候选交易?不应要求调用者先理解编译器内部元数据。本 issue 设计可选 SSRI 兼容入口及其与已有 builder 的边界,总选型由 #81 决定,也可能缩小范围或延期。
从现有机制出发,而非重新建立信任
CellScript 已有编译后的 ELF、类型接口、独立 checker 和 ProtocolBundle。#28/#29 负责实现及角色准入,#80 进一步检查完整 Script args 和实例。这些机制解决“允许谁参与”;SSRI 候选解决“工具如何发现和使用”。例如发行者合法发行类别 6 凭证,观察者策略只允许类别 1–5:SSRI 可以显示类别 6,不能因此使观察者接受它。
上游依据及差异
ckb-ssri-std@ 93f3a779。方法宏 使用短方法 hash 与 hex argv;fallback 区分空 argv 与特殊链下 VM version。get_cell_deps,所查ssri_methods!分发表只有 version/get_methods/has_methods。声明兼容时必须逐方法列明支持范围。上述是固定源码观察,尚未进行 SSRI server 互通实验。
v1 用例及范围
先用非金融凭证,避免混入资产经济规则:
前两步可以先实验,第三步取决于总选型与候选交易边界。评审前不向稳定语法加入新方法或返回结构;不将 SSRI 公共 UDT trait 强加给凭证,自定义 namespace 单独声明。
三种集成方式必须比较
比较标准包括:真实外部客户端互通、身份可核验程度、升级错配、二进制体积与运行预算、维护复杂度。尚未预选。
上下文、来源与缓存
每个方法须明确最低执行环境与读权限:Code 不能凭空得到实例;Script 必须绑定完整 code_hash/hash_type/args;Cell 绑定 OutPoint 与快照;Transaction 绑定交易、输入快照、网络与必要依赖。实时链查询还要记录查询结果和观察 tip,相同代码在不同链状态下未必返回同一结果。
结果 provenance 至少包含执行代码 hash/OutPoint、接口与方法版本、完整 context hash、request/response hash、执行器版本及预算消耗。这只是供来源核验,不能依赖自称真实的 JSON 字段,更不赋予花费权限;调用方必须验证或独立重放。
缓存键包含代码、实例、方法、参数、上下文和链快照。Type ID 更新、Cell 被消费、reorg 或输入快照变化必须失效,不能仅按 code hash 缓存不同实例。返回交易还须检查原始签名意图的金额、收款人、费用和 capacity;SSRI server 不保管私钥。
编码、错误与预算
limit=0表示“全部”,但宿主内部仍必须有硬上限;超限明确失败或采用版本化分页,不能静默截断又声称完整。实施与测试
作者接口方向 — 2026-10-19
将 #47/#48/#49 的作者接口要求应用到候选发现与构造接口。冻结公开语法前,评审具名方法、类型化参数/结果、所需上下文和具名资源上限的声明方式。在支持范围内,从同一份规范接口契约派生发现描述及客户端/builder 绑定,避免作者在每次调用中重复方法签名、位置参数上限或编译器内部 view 类型。逐项记录无法保留选定 SSRI 协议语义的映射;生成调用代码本身不证明 wire 兼容。
作者代码须区分代码、具体 Script 实例、Cell 快照与交易上下文。便利的上下文对象不能悄悄用代码身份替代完整实例身份、选择链快照或授予签名权。字段及策略应结构化解析,避免把普通字段引用藏在不透明策略字符串中。候选交易构造仍须明确用户意图,并经过现有准入与签名检查。
查询/codec helper 在无需保留 view 时优先直接读取,只有生命周期有实际意义时才引入显式 borrow 作用域。以有界且不逃逸的 helper 组合为设计目标,不声称已经支持。宿主返回值是具有待核验来源的有界类型化数据,不是借来的链上 Cell view,也不是拥有所有权的资源。嵌套结果须使用声明的 #48 codec 及上限;链下 SDK 分配内存不意味着已支持 #47 链上堆。
稳定 API 评审前,提供完整的“发现 → 实例查询 → 候选交易”示例,包含作者声明、生成的消费者调用、可复用 helper,以及畸形/过期上下文的拒绝路径。明确标注拟议语法和未支持用例。三种集成位置均用相同作者工作流评估;选择同 ELF、伴随 ELF 或 adapter 不应自动决定公开写法。
依赖与关闭条件
#28/#29/#80 仍负责准入。#47/#48/#49 不因本设计重新开启或被视为完成;固定长度查询不依赖通用 allocator。链上嵌套变长结果需 #48 相关 codec,链下宿主支持动态数据不表示链上语言已支持;Cell 集合转移由 #49 负责,owned 动态集合才涉及 #47。
请 Hanssen、Retric、Guopeng 及其他评审者帮助确认:哪些方法优先?伴随 ELF 是否满足预期语义?目前规范与实现冲突以谁为准?哪些链下信息需要来源证明或重放?若只有 adapter,如何命名才不会误导?提及姓名不代表已收到审核意见。
Design workstreams / 阅读
总选型 #81;链上 IPC 生命周期 #83;本议题 #82。发现及上下文实验不必等待通用链上 IPC。
端到端教程。