Repository navigation
[Candidate][Consensus runtime] Implement executable bounded Cell-group consumption #7
Description
Summary
Implement the positive runtime semantics for BoundedCellSet<T, N>::consume_each on the CKB target.
The frontend already preserves the bounded operation and its predicate, but production builds correctly reject it because the emitted verifier does not yet select, authenticate, decode, count, and discharge the lifecycle of every matching input Cell. This issue is complete only when the selected shape executes in CKB-VM and the standalone checker can prove that the corresponding machine blocks are present.
This is a consensus-facing feature. An accepted specification must precede positive lowering.
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.
Why this is a real gap
Today, N is only a static complexity declaration. It is not evidence that runtime execution observed at most N Cells. The current boundary is documented in the collections support matrix.
Explicit fixed-arity parameters work, but they do not express protocols whose input cardinality is bounded yet chosen by each transaction—for example batched account updates, bounded receipt settlement, or a capped set of claims.
Argent's open range PR #44 is a useful design signal, not production evidence: its runtime builder and several interaction classes remain follow-up work. CellScript must define the CKB Script Group, Molecule, identity, and linear-lifecycle contract directly.
Required semantic contract
The first accepted version should be deliberately narrow:
- support Type Script group inputs first;
- require an explicit group source; never scan the whole transaction implicitly;
- bind
Tto an exact Type Script identity and canonical schema; - compute the actual group cardinality in CKB-VM and require
actual_count <= N; - decode every selected Cell exactly once;
- execute the predicate exactly once for every decoded element;
- fail the whole Script on any predicate, identity, source, count, or decoding failure;
- discharge every selected Cell through the linear
consumelifecycle; - preserve canonical group-relative order in metadata, traces, and builder evidence.
Lock Script support must be a separate explicitly justified shape if its observable group and authority rules differ.
flowchart LR
TX["Candidate CKB transaction"] --> SG["Exact Type Script group inputs"]
SG --> COUNT["Load actual group count"]
COUNT --> BOUND{"count <= N?"}
BOUND -- "no" --> REJECT["Stable runtime error"]
BOUND -- "yes" --> LOOP["For each group-relative input"]
LOOP --> ID["Verify Script identity"]
ID --> DECODE["Decode canonical Molecule T"]
DECODE --> PRED["Run predicate exactly once"]
PRED --> LIFE["Record/discharge consume"]
LIFE --> ACCEPT["All selected Cells covered"]
Required failure taxonomy
Each failure must have a stable registered runtime error and a source-linked ProofPlan obligation:
| Failure | Required behavior |
|---|---|
| wrong source kind | Reject before trusting data |
| wrong Type Script identity | Reject the selected Cell |
| missing or ambiguous identity | Reject; never fall back to schema-only matching |
| malformed Molecule data | Reject with a decoding-specific error |
actual count greater than N |
Reject before iteration |
| duplicate logical identity | Reject when the resource policy requires uniqueness |
| predicate returns false | Reject the complete transaction |
| predicate or decode path omitted by codegen | Standalone checker mutation must reject the artifact |
| lifecycle not discharged | Compile-time ownership error or production rejection |
Implementation phases
Phase 0 — specification
Add an accepted bounded-lifecycle RFC covering:
- observable source and group ordering;
- Type Script identity policy;
- canonical Molecule codec;
- zero-input semantics;
- uniqueness policy;
- predicate evaluation and side-effect rules;
- error-code allocation;
- ProofPlan and typed-semantics records;
- Lock versus Type Script differences;
- cycle, stack, and serialized-size budgets.
No positive runtime lowering should land before this phase is accepted.
Phase 1 — typed and metadata boundary
- keep the predicate and source selection in typed semantics;
- make actual-cardinality observation explicit;
- add independent ProofPlan records for selection, identity, decode, count, predicate, and lifecycle discharge;
- update entry ABI and builder assumptions;
- ensure the executable-surface classifier distinguishes the newly supported shape from all unsupported variants.
Phase 2 — CKB runtime lowering
- use canonical Script Group input syscalls;
- enforce actual count before iteration;
- lower a bounded loop with deterministic memory use;
- decode each element once and retain a typed addressable view;
- propagate exact runtime errors;
- keep unsupported shapes fail-closed with E2105.
Phase 3 — verification and tooling
- extend the standalone artifact checker and mutation corpus;
- add simulator, CKB-VM, and stateful CKB acceptance fixtures;
- update builder validation, LSP, VS Code, Playground summaries, docs, and release notes;
- measure worst-case cycles, stack, code size, transaction size, and occupied capacity.
Acceptance matrix
The same fixture identity must be exercised in simulator, CKB-VM, and the stateful harness.
| Case | Expected |
|---|---|
| zero matching inputs, when minimum is zero | pass |
| one matching input | pass |
exactly N matching inputs |
pass |
N + 1 matching inputs |
stable count error |
| wrong Type Script hash | stable identity error |
| malformed Molecule payload | stable decode error |
| predicate false on first/middle/last element | same predicate error |
| duplicate logical identity | stable identity-policy error |
| transaction-wide match outside the Script Group | ignored or rejected according to the accepted source rule; never silently selected |
| removed count/identity/decode/predicate machine block | standalone checker rejects the mutation |
Completion criteria
- The bounded-lifecycle RFC is accepted.
- A selected supported shape no longer emits runtime error 24 or E2105.
- Unsupported sources and element shapes remain fail-closed.
- Typed semantics and ProofPlan record actual runtime cardinality observation.
- The machine lowering has deterministic mutation coverage.
- Simulator, CKB-VM, and stateful CKB fixtures agree.
-
dev,ci, andbackendgates pass. - At least one independent security review focuses on source selection, identity, decoding, and lifecycle coverage.
- Release evidence includes worst-case cycles and size bounds.
Non-goals
- allocator-backed collections;
- arbitrary transaction-wide queries;
- unbounded loops;
- generic Cell-backed collection returns;
- implicit schema-only identity;
- hiding builder assumptions as on-chain authorization;
- implementing
create_eachin this issue.
Activity
a19q3 commentedon Aug 27, 2026
Research update after reviewing Argent PR #44 and the current CellScript lowering
Comment audit
There were no prior comments on this issue at the time of review, so there is no unresolved maintainer feedback to answer here.
Argent PR #44 does have active review discussion. The most important items are:
The complete review note is also visible at:
https://github.com/argent-lang/argent/blob/84cb74b65a7d4b8218ce505009ff017312fdf990/docs/entry-ranges-review.md
What the Argent review actually changes for this issue
The strongest lesson is not merely “add a bounded loop.” It is that the loop element must retain its physical input-reference identity.
Argent's scalar consumed actor value denotes an input reference. The current range branch instead makes accounts[i] behave like an already-decoded authored state value. That erases the distinction between:
The review proposes the more precise relationship:
CellScript needs the same separation even though its vocabulary is CKB-specific. A BoundedCellSet element should not become T before the source, Script identity, count, data length, and codec have been checked. The internal model should preserve something equivalent to GroupInputRef plus a separately authenticated decoded T.
Required execution order
The first supported shape should enforce this order in generated code and evidence:
This maps directly to CKB's consensus model: GroupInput is the current Script Group view, while transaction-wide Input is a different explicit source. See the official transaction and syscall specifications:
ABI hardening requirement
Argent's review found a second, independent issue: ordinary builder encoding was producing valid shapes, but the decoder path could still read dynamic struct-array leaves without first validating the claimed leaf cardinality. This is exactly the distinction this issue already tries to preserve: builder behavior is not consensus evidence.
For CellScript, the accepted RFC should require all of the following before an element is addressable:
The standalone checker mutation corpus should delete or bypass each class of guard independently.
Scope refinement
The Argent review also recommends deferring expanded consumed ranges because an expanded element may not have a complete authored state without a validated opening. CellScript should make the same conservative choice:
The reported impossible-range example around unrestricted(next[3].value) is another useful warning: every compile-time range constraint must be checked for satisfiability, and unreachable index assumptions must not silently become runtime obligations.
Acceptance additions
Please add explicit tests for:
Conclusion
The issue remains correctly classified as P0, but the implementation target should be described as “bounded authenticated input-reference iteration,” not merely bounded collection iteration. Argent #44 is useful because its current review exposes the exact abstraction leak CellScript must avoid; it is not evidence that the feature is complete upstream.
The current CellScript fail-closed boundary is still honest and correct:
CellScript/docs/CELLSCRIPT_COLLECTIONS_SUPPORT_MATRIX.md
Lines 20 to 29 in 8ae6dc4
CellScript/src/executable_surface.rs
Lines 356 to 374 in 8ae6dc4
CellScript/src/proof_plan/mod.rs
Lines 310 to 340 in 8ae6dc4
[-][0.26][P0] Implement executable bounded Cell-group consumption[/-][+][Candidate][Consensus runtime] Implement executable bounded Cell-group consumption[/+]a19q3 commentedon Sep 12, 2026
0.30 closure update: the admitted bounded Type-group input contract is complete. Native BoundedCellSet input now enumerates the complete canonical GroupInput set, checks runtime cardinality in 0..=N before iteration, preserves authenticated physical references through fixed-width decoding, evaluates the declared per-element predicate/accumulator, and discharges lifecycle coverage. Unsupported sources and shapes remain fail-closed.
The independent checker and mutation corpus bind count, source, identity, decode, predicate, and lifecycle machine blocks; simulator, CKB-VM, stateful, and production-node evidence agree. The clean release replay at 3cf60a1 passed, including pinned CKB 0.207.0 production admission with complete 43-action/17-lock coverage.
Independent review was explicitly waived by the maintainer for this bounded 0.30 scope; it was not performed or claimed as passed. Generic transaction iteration, non-Type roles, arbitrary loop effects, and dynamic outputs remain outside this issue. Closing as complete for the accepted contract.