Transient storage as its own address space - #8
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Transient storage (EIP-1153) gets its own tab and its own grid. It is never merged with persistent storage, because both spaces number from 0 — in the probe that shaped this design, the persistent `persistent` is slot 0 and the transient `lock` is slot 0 — so a merged view would make slot 0 mean two things at once. Keeping them apart is the lesson, not an implementation detail. Probed against the locked solc 0.8.36 before designing anything: - transientStorageLayout exists with the same shape as storageLayout, so decodeStorageLayout and buildRows work on it verbatim; - packing is identical (two uint128 transient vars share slot 2 at 0 and 16); - transient is VALUE TYPES ONLY — mapping, struct and static array are rejected with UnimplementedFeatureError. That last point is why this phase is small: the transient grid needs none of the v1.2/v1.4 reference machinery. No reserved heads, no derived children, no elided ranges. StorageGrid is reused unchanged behind a `space` prop that only selects copy and switches derived-child reconstruction off, since reconstructing against persistent keccaks could only invent a link. Transient accesses are now named: resolveAccesses takes an optional transient layout and routes strictly by kind, so neither index is ever consulted for the other space's accesses. docs/limitations-v1.0.md is updated accordingly — that entry was true only while the persistent layout was the sole index. Honesty about lifetime is carried in permanent text, not styling. Before a run: "transient storage is empty outside a transaction". After one: "observed during the transaction, discarded when it ended". The tab itself appears only when the contract declares transient variables, so its absence is compiler truth rather than a UI accident. The locked Standard JSON snapshot moved deliberately to request the new output. Fixture goldens verify unchanged, which confirms the added selection changes what solc reports, not what it compiles. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
halaprix
force-pushed
the
feat/transient-storage
branch
from
July 31, 2026 07:21
a9df18f to
61f65b5
Compare
…e leaks Confirmed by an independent Codex + Gemini 3.6 Flash review of this PR, then verified directly against source before fixing anything. - useExecutionSession.ts called resolveAccesses without transientLayout, so the transient naming this PR added was correct and unit-tested but unreachable from the actual app: every tload/tstore in the UI stayed unresolved. Both reviewers found this independently. Pass artifact.transientStorageLayout through. - resolve.ts's lastValueBySlot was one map keyed by slotHex alone, shared across persistent and transient accesses. Persistent and transient storage both number from 0, so a persistent write to slot 0 followed by a transient write to slot 0 — exactly what the existing test contract does (persistent = 1; lock = 9;) — handed the transient access the persistent word as its previousValueHex, producing a false byte-diff instead of the honest "first touch" state. Keyed the map by space + slot instead. Verified the new test fails without this fix (previousValueHex was the persistent word, not null) and passes with it. - packages/challenges' compileArtifact()/bankRunner() test helpers built ContractArtifact literals missing the now-required transientStorageLayout field. This package isn't in the root tsconfig's project references, so pnpm typecheck never touched it — confirmed by reading tsconfig.json directly and by running tsc --noEmit on the package in isolation, on both this branch and master. Not a currently-failing gate, but a real type error; set the field to null in both helpers. New coverage: a unit test in chains.test.ts asserting previousValueHex stays null on first touch across a space boundary, and two e2e tests confirming a transient write is actually named in the runtime write log (not "unresolved slot") and that its previous-value display shows "first touch" rather than a cross-space byte diff. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
docs/design/transient-storage-v1.5.md. Closesslotscope-syp(.1–.3).Why it is a separate space, not a second column
Transient storage (EIP-1153) numbers from 0 in its own address space. In the
probe that shaped this design, the persistent
persistentis slot 0 and thetransient
lockis slot 0. A merged view would make slot 0 mean two things atonce, so transient gets its own tab and its own grid. Keeping them apart is the
lesson, not an implementation detail — there is an e2e that asserts neither grid
ever shows the other's name.
What solc actually gives us
Probed against the locked solc 0.8.36 before designing anything, because the
whole shape depended on it:
transientStorageLayoutalready exists, same shape asstorageLayout. SodecodeStorageLayoutandbuildRowswork on it verbatim — no new decoder. Itsimply was not in our
outputSelection.uint128 transientvariables shared slot 2 at offsets0 and 16.
mapping, structs and static arrays are rejected withUnimplementedFeatureError: Transient data location is only supported for value types.Point 3 is why this phase is small: the transient grid needs none of the v1.2/v1.4
reference machinery — no reserved heads, no keccak-derived children, no elided
ranges.
StorageGridis reused unchanged behind aspaceprop that selects copyand switches derived-child reconstruction off, since reconstructing a transient
slot against persistent keccaks could only invent a link.
Transient accesses are finally named
docs/limitations-v1.0.mdrecorded that transient accesses never resolve. That wastrue only while the persistent layout was the sole index — naming them against it
would have named the wrong variable.
resolveAccessesnow takes an optionaltransient layout and routes strictly by kind, so neither index is ever consulted
for the other space's accesses. Without this the tab could label nothing.
Honesty about lifetime
Transient state is discarded when the transaction ends, so the tab never claims a
"current" value. Two permanent text lines carry it, not styling:
transient storage is empty outside a transaction;observed during the transaction · discarded when it ended.The tab itself appears only when the contract declares transient variables, so its
absence is compiler truth rather than a UI accident.
Note on the locked input
The Standard JSON snapshot moved deliberately to request the new output. Fixture
goldens verify unchanged, which confirms the added selection changes what solc
reports, not what it compiles — the property that matters for a locked
environment.
Verification
format:check,lint,typechecktest:unittest:e2efixtures:verifyrelease:verifybuild:checkbenchmark:v0.1🤖 Generated with Claude Code