Repository navigation
[0.31][ABI] Right-size entry frames and evaluate policy argument copy removal #33
Description
Engineering closure — 2026-09-25
Engineering closure through 0.31 follows the maintainer’s September 25 instruction to skip #30 and exclude 0.32. Release version promotion, fresh distribution bundles, the final release gate and independent release review remain under #30. This closure neither transfers the 0.30 review waiver nor claims an independent security audit or published 0.31 release.
Commit 648bb836, boundary review and acceptance map, isolated attribution, and reproduction/coverage map reconcile the checklist below.
Accepted decisions — 2026-09-21
D4: reduce selected policy-adapter private frames using proven parameter/helper requirements. Keep outer WitnessArgs capacity, overlapping normalization, and parent-to-adapter copy ownership unchanged. Unknown requirements use the existing bounded layout. Borrowing, word-copy changes, and staged outer loading are deferred to a follow-up targeting 0.32.
Full decision record — baseline: 8d6e200caa58d81429912df925a9322f691cb41d; research baseline remains 6d75a6e7. The choices below were the original open questions; this decision record now governs implementation. The issue stays open until its implementation acceptance passes.
Parent: #30
Target: 0.31. Baseline: branch 0.30, commit 6d75a6e7e4ce55b940697428d895eda74a51ca86. Implementation and engineering acceptance are complete; the accepted decisions define the bounded scope and deferred work.
Problem and evidence
The entry wrapper reserves a 5,376-byte base frame, including a 4,096-byte witness buffer and 1,024-byte Script buffer: src/codegen/mod.rs. Small fixed-width parameters use the same base layout.
The policy adapter copies selected arguments byte by byte into a private buffer before decoding: src/codegen/abi.rs. The independent checker explicitly enforces the private frame and copy loop: crates/cellscript-artifact-checker/src/checker.rs.
Frame bytes are reserved address space, not an instruction count. A smaller frame does not imply a proportional cycle saving.
Decisions to record
- Which buffer bounds can be derived from the selected entry, its parameter layout, and its admitted runtime operations? What bounded fallback remains for dynamic cases?
- Does reducing a buffer accidentally reject an input previously admitted by the same ABI? Distinguish semantic payload bounds from loader capacity and preserve the accepted input set.
- Retain a private copy, use a faster bounded copy, or decode through a borrowed read-only span? Start with frame sizing; admit borrowing only after documenting parent-buffer lifetime, nested calls, aliasing, and clobber rules.
- How should these ownership and frame rules be represented and independently checked? Decide schema compatibility/versioning before changing current machine patterns.
Acceptance
- Record frame-sizing and copy-ownership decisions separately.
- Demonstrate a smaller safe frame for selected small/payload-free entries; retain a tested fallback where static sizing is insufficient.
- Test empty/exact-bound/over-bound/truncated inputs, fixed bytes wider than eight bytes, Script args, nested helper calls, and outgoing arguments that use the stack.
- Prove saved return addresses, caller-owned buffers, and outgoing argument areas remain disjoint; add negative artifact mutations for the new contracts.
- Report ELF, successful and rejection cycles, per-entry frame sizes, and a separately named call-chain stack metric. Do not relabel the old maximum-individual-frame metric as a dynamic peak.
- Preserve witness bytes and wire ABI for the initial implementation; any protocol change needs its own explicit decision.
- Run
./scripts/cellscript_gate.sh backendfor the implementation and./scripts/cellscript_gate.sh cibefore claiming merge readiness. Retain fresh cost reports from the exact tested commit. Preserve accept/reject behavior and independent artifact validation; changes to machine contracts must update producers, checker, lowering records, source maps, and negative mutation tests together.
Coordinate with policy adapter sharing. Keep buffer layout in frame/ABI owners and keep the checker independent of compiler implementation code.
Activity
a19q3 commentedon Sep 21, 2026
Research notes, 2026-09-21. CellScript source checked at
6d75a6e7. These are proposed experiments and decisions, not implementation results.The policy path has two distinct copy operations, and they have different safety conditions.
Copy inventory
A faster copy must handle the correct overlap direction and exact tail bounds. Replacing byte loads with word loads also needs an explicit alignment/access contract; reading beyond the validated span is not acceptable.
Using the pinned CKB-VM instruction cost model, the adapter's present seven-instruction loop has a static instruction-cost sum of 15n + 3 for n copied bytes, excluding setup and surrounding code. That gives 603 for 40 bytes and 2,043 for 136 bytes. These are analytic loop estimates, not measured transaction savings. The earlier WitnessArgs move is a separate loop and copies a different span.
Why parameter width alone cannot size the outer buffer
The normalizer permits optional lock and output_type fields and checks their framing too. A small input_type does not imply a small complete WitnessArgs. Likewise, one selected policy record does not bound the other records in its envelope.
The CKB syscall RFC's partial-loading contract distinguishes bytes copied from the available length reported through the length pointer. A smaller buffer therefore requires a deliberate loading/validation strategy, not just a smaller allocation constant. A staged reader could retain the admitted input set, but additional syscalls and validation have their own cost.
Suggested implementation order
The RISC-V ABI requires 16-byte stack alignment for the standard ABI and does not preserve storage below sp. Preserve CellScript's outgoing-argument isolation as well.
Decisions to record: separate outer loading capacity, selected-argument storage and borrowing. A smaller private adapter is the suggested first candidate; zero-copy remains conditional on ownership and checker evidence. Include large optional WitnessArgs fields, first/last selected records, nested calls and malformed final fields in acceptance tests.
a19q3 commentedon Sep 23, 2026
Review after the 0.31 implementation, 2026-09-23.
D4's private-frame sizing is implemented at
65df937f. The outer 4,096-byte WitnessArgs capacity, overlapping normalization move, and parent-to-adapter copy remain intentional. Unknown requirements retain the bounded fallback. See the adapter implementation, accepted D1–D6 decisions, and the final implementation and validation record.Remaining work:
Close this child after the exact frame/ownership contract and its evidence receive the required boundary review. The remaining copy operations alone are not a reason to keep the accepted 0.31 implementation open.
a19q3 commentedon Sep 25, 2026
Engineering acceptance complete at 648bb836.
Validation on clean commit
648bb8362a82586821c0d4ae9f8b2250dd56ab11: localdev, fullci, and fullbackendpassed; GitHub CI also passed and retains the fresh cost/shape/strict-audit artifacts. The final clean-source cost pair passes another 6,782-metric comparison against the archived candidate. The full backend gate rebuilt pinned CKBf7fa4436and passed the local-node 43-action, 17-Lock and 26-stateful-scenario matrix. Local acceptance report SHA-256:8a1aeb4221409f187e82a342c7335db19432a3fd800e9182e1c65806655a889c. This is local-node evidence, not a new public-network deployment.The engineering review maps fixed-capacity derivation, fallback, private-copy ownership, saved ra and temporary outgoing arguments to source, VM cases and rebound artifact mutations. A new regression combines a shared decoder, wide/stack arguments and a saved-ra mutation into the payload region; the independent checker rejects it. In the fixed 32-byte policy sample, private adapters reserve 64 bytes, the parent reserves 4,192, and the static call-chain bound is 6,160. The outer 4,096-byte input boundary and private copy remain. These are static bounds, not observed peaks; #38 owns borrowing/copy changes.
Boundary review / acceptance map · attribution and exact report pairs · frozen coverage and reproduction.
Engineering closure through 0.31 follows the maintainer’s September 25 instruction to skip #30 and exclude 0.32. Release version promotion, fresh distribution bundles, the final release gate and independent release review remain under #30. This closure neither transfers the 0.30 review waiver nor claims an independent security audit or published 0.31 release.