Repository navigation
[Candidate][Consensus runtime] Implement executable bounded output-plan correspondence #8
Description
Summary
Implement the positive runtime semantics for BoundedList<P, N>::create_each.
The compiler already retains the plan predicate and create template, but production builds correctly reject the operation because there is no canonical witness codec or on-chain proof that every plan corresponds to exactly one output Cell in the required order, with the required identity, Script, data, lock, and capacity.
This issue depends on the selection and decoding foundations in #7, but it remains separate because output authorization and one-to-one correspondence have a larger attack surface than bounded input consumption.
Portfolio status
This is a candidate consensus-runtime workstream, not an authorized 0.26 or P0 implementation commitment. Until the post-0.25 evidence review accepts concrete use cases, an accountable owner, an independent reviewer, capacity, and stop conditions, only Phase 0 specification and use-case discovery are authorized. The issue priority describes semantic risk, not a promised release slot.
Security statement
A transaction builder may construct a plausible transaction, but builder behavior is not a consensus boundary. The emitted CKB Script must independently prove:
plan count == selected output count <= N
and
for every i: plan[i] authorizes exactly selected_output[i]
Missing, extra, duplicated, or reordered outputs must fail on chain.
flowchart LR
W["WitnessArgs.input_type"] --> CODEC["Decode versioned PlanList<P>"]
CODEC --> PC["plan_count"]
GO["Canonical group-relative outputs"] --> OC["output_count"]
PC --> EQ{"plan_count == output_count <= N?"}
OC --> EQ
EQ -- "no" --> REJECT["Stable correspondence error"]
EQ -- "yes" --> ZIP["Zip plan[i] with output[i]"]
ZIP --> SCRIPT["Verify Type/Lock Script policy"]
SCRIPT --> DATA["Verify canonical output data"]
DATA --> CAP["Verify occupied capacity floor"]
CAP --> ID["Verify fresh/preserved identity policy"]
ID --> ACCEPT["Every pair covered exactly once"]
Required semantic contract
The first supported shape should require:
- a versioned canonical Molecule list in
WitnessArgs.input_type; - a compile-time maximum
Nand runtime count enforcement; - canonical Type Script group-relative output ordering;
- exact one-to-one plan/output correspondence;
- one evaluation of each plan predicate and one materialization of each output template;
- explicit Type Script, Lock Script, data schema, and capacity policies;
- an explicit identity rule for every created resource;
- stable failures for omission, duplication, reordering, malformed plans, and under-capacity outputs;
- builder evidence that mirrors—but never replaces—the checks performed by the Script.
The accepted RFC must decide whether the initial version permits zero plans. It must not infer freshness or authority from action/function names.
Correspondence model
sequenceDiagram
participant B as Transaction builder
participant W as Witness PlanList
participant T as Candidate outputs
participant V as CellScript verifier
B->>W: encode versioned plans
B->>T: construct candidate outputs
V->>W: decode and bound count
V->>T: select canonical group outputs
loop each index i
V->>V: validate plan[i] against output[i]
end
V-->>B: accept only if all pairs and counts match
The builder and verifier must use the same ordering specification. A global-index witness is acceptable only if the Script proves uniqueness, monotonicity, group membership, and complete coverage.
Required failure taxonomy
| Failure | Required behavior |
|---|---|
| missing or empty required witness field | stable witness/codec error |
| unknown plan codec version | reject |
| malformed offset table or truncated item | stable Molecule error |
plan count greater than N |
stable count error |
| fewer outputs than plans | stable missing-output error |
| more outputs than plans | stable extra-output error |
| reordered outputs | stable correspondence error |
| duplicate plan or output index | stable duplication error |
| wrong Type Script or Lock Script | stable Script-policy error |
| wrong data/schema | stable output-data error |
| insufficient capacity | stable capacity error |
| reused identity where freshness is required | stable identity error |
| machine block removed | standalone checker rejects the mutation |
Implementation phases
Phase 0 — specification
Extend or add an accepted RFC that fixes:
- witness field and Molecule schema;
- codec versioning and canonical encoding;
- output selection source and ordering;
- count and zero-element behavior;
- one-to-one correspondence;
- Script/data/lock verification;
- occupied-capacity policy;
- fresh and preserved identity policies;
- ProofPlan and typed-semantics records;
- error codes and resource budgets.
Phase 1 — codec and typed boundary
- generate and verify the canonical plan-list codec;
- bind codec identity into entry ABI and metadata;
- retain the full create template and predicate in typed semantics;
- add separate ProofPlan obligations for decode, count, selection, ordering, pair correspondence, identity, and capacity;
- make the builder manifest generate a fillable but non-authoritative plan skeleton.
Phase 2 — CKB runtime lowering
- decode once with strict bounds;
- select group-relative outputs canonically;
- compare counts before materialization;
- lower a deterministic bounded pair loop;
- verify all output fields the compiler claims are constructed;
- retain fail-closed behavior for every unsupported shape.
Phase 3 — independent verification and builder parity
- teach the standalone checker to link every pair-validation block to typed semantics and source ranges;
- add mutations deleting or bypassing count, ordering, identity, capacity, and data checks;
- ensure generated builders and
cellc tx validateuse the same ordering and codec; - run every positive and adversarial fixture in simulator, CKB-VM, and the stateful harness.
Acceptance matrix
| Case | Expected |
|---|---|
| zero plans/outputs when allowed | pass |
| one plan/output | pass |
exactly N pairs |
pass |
N + 1 plans |
stable count error |
| missing output | stable missing-output error |
| extra output | stable extra-output error |
| reordered outputs | stable correspondence error |
| duplicated plan or selected output | stable duplication error |
| wrong Type Script | stable Script-policy error |
| wrong Lock Script | stable Script-policy error |
| wrong data payload | stable schema/data error |
| under-capacity output | stable capacity error |
| reused Type ID or logical identity | stable identity error |
| valid builder output with one adversarial post-build mutation | CKB-VM rejects |
| removed correspondence block in ELF | standalone checker rejects |
Completion criteria
- An accepted RFC fixes the codec, ordering, identity, and capacity contracts.
- Supported shapes no longer emit runtime error 24 or E2105.
- Unsupported output collections remain fail-closed.
- The builder and Script share one versioned plan/order specification.
- Every plan/output pair is verified on chain exactly once.
- Standalone checker mutations cover count, ordering, pair, identity, data, lock, type, and capacity checks.
- Simulator, CKB-VM, stateful acceptance, and
tx validateagree. - Worst-case cycles, stack, code size, transaction size, and occupied capacity are recorded.
-
dev,ci, andbackendgates pass. - Independent security review is complete.
Non-goals
- arbitrary allocator-backed output vectors;
- transaction-wide fuzzy matching;
- builder-only authorization;
- implicit output ordering;
- identity inferred from source names;
- Cell-backed collection return values;
- ranged foreign-Script composition, which belongs to a protocol-composition design.
Dependencies
- [Candidate][Consensus runtime] Implement executable bounded Cell-group consumption #7 — executable bounded Cell-group consumption foundations.
Activity
a19q3 commentedon Aug 27, 2026
Research update: output ranges need a stricter consensus codec than the builder path
Comment audit
There were no prior comments on this issue at the time of review.
Argent PR #44 has active review comments, and the dynamic array ABI finding is directly relevant to create_each:
Argent's route/output coverage work in PR #1 and bounded emits work in PR #44 are useful design signals, but neither changes the CKB requirement that the Type Script independently prove output correspondence.
Sharpened CKB model
For the first supported Type Script shape, the selected output set should be the complete GroupOutput view for the current exact Type Script. That gives a consensus-defined ordering and automatically makes an extra output with the same Type Script visible to the count check.
The core invariant should be evaluated from independently obtained values:
A builder-supplied list of global output indexes is a more complex later shape. If allowed, the Script would also need to prove strict monotonicity, uniqueness, group membership, in-range indexes, and complete group coverage. The group-relative form is safer for v1.
Decoder requirements
The PR #44 ABI review demonstrates why a canonical encoder is insufficient. Before reading plan[i], the CKB runtime must validate:
A plan count that is less than or equal to N is not enough if the corresponding offsets can address outside the validated byte region.
The builder, simulator, CKB-VM runtime, and independent checker should share golden vectors, but the on-chain decoder must not assume those producers were used.
Pair validation should be explicit
For each pair, the runtime should keep separate ProofPlan/checker obligations for:
This prevents a future optimization from replacing “verify constructed output” with “trust generated template.”
Occupied capacity deserves special care: it must be calculated from the actual output capacity, lock script, optional type script, and data length, not from a builder estimate or a type-only constant.
Relationship to #7
The issues should share:
They should not share the source semantics:
Keeping them separate avoids treating a witness plan as a Cell or a GroupOutput as authored plan state.
Acceptance additions
Please include adversarial cases for:
Scope recommendation
The first version should remain:
Cross-Script output coordination belongs in #9/#10 after this local one-to-one verifier is complete.
Conclusion
The issue remains valid and appropriately separate from #7. The most important research result is that the canonical PlanList contract must specify both the normal encoding and every rejection condition. Argent's current range review shows that “the builder emits valid arrays” is not enough; CellScript's completion criterion must be adversarial decoder safety plus complete GroupOutput correspondence.
Current honest boundary:
CellScript/docs/CELLSCRIPT_COLLECTIONS_SUPPORT_MATRIX.md
Lines 20 to 29 in 8ae6dc4
CellScript/src/executable_surface.rs
Lines 366 to 374 in 8ae6dc4
[-][0.26][P0] Implement executable bounded output-plan correspondence[/-][+][Candidate][Consensus runtime] Implement executable bounded output-plan correspondence[/+]a19q3 commentedon Sep 12, 2026
0.30 closure update: the admitted fixed-width bounded output-plan contract is complete. CSBPLv1 composes inside the canonical CSARGv1 WitnessArgs.input_type envelope; the verifier independently enforces bounded plan count, complete canonical GroupOutput order, exact one-to-one count/correspondence, data, Lock, Type, capacity, and identity policy. Generated builders, ProtocolBundle/adapter validation, independent machine checks, adversarial mutations, CKB-VM, stateful, and production evidence cover the same contract.
The clean release replay at 3cf60a1 passed, including the final product and local-node gates. Independent review was explicitly waived by the maintainer for this bounded 0.30 scope; it was not performed or claimed as passed. Computed/dynamic templates, foreign Script output roles, and unbounded plans remain fail-closed and out of scope. Closing the accepted issue.