Skip to content

Ground keccak chains for nested reference heads - #5

Merged
halaprix merged 1 commit into
masterfrom
fix/nested-reference-heads
Jul 30, 2026
Merged

Ground keccak chains for nested reference heads#5
halaprix merged 1 commit into
masterfrom
fix/nested-reference-heads

Conversation

@halaprix

Copy link
Copy Markdown
Owner

The defect

A mapping, dynamic array or bytes/string declared inside a struct or an
array element
could not be named at all. Every access to one resolved as
unresolved — the product silently failed to name storage it otherwise
understands perfectly.

buildStaticIndex built variableBaseSlots from layout.storage
(packages/semantics/src/resolve.ts:60-63), which lists top-level entries
only
. For struct Nested { uint256 head; mapping(address => uint256) inner; }
the layout entry is nest; the mapping member is not there. So
referenceVariablesBySlot (chains.ts:31) never saw the head,
groundHash could not ground keccak(key ‖ headSlot), and the chain died.

This was found while planning slotscope-xu8 (v1.4). The first diagnosis was
that a nested head merely lost its display name; it is worse than that — the
resolution never happens.

The fix

buildStaticIndex already decodes the layout to populate cellsBySlot, and that
model carries every nested head as a CollapsedStorageSpan with its exact base
slot, its dotted path (nest.inner, pairs[1].m) and — since #4 — the solc
encoding. Index those spans too. Eight lines, no new traversal, no new source of
truth.

Two consumers get the same repair for free, because both look variables up in
that index: string/bytes migration annotation (resolve.ts:226) and the
bytes-data chunk labels (chains.ts:277). Nested bytes/string heads now
annotate correctly as well.

Verification

The new test in chains.test.ts compiles and executes a real contract rather
than asserting against a hand-built layout, and was confirmed failing first
(expected 'unresolved' to be 'exact'). A write to nest.inner[addr] now
resolves exact as nest.inner[0xaa…] with its value decoded.

Gate Result
format:check, lint, typecheck clean
test:unit 236/236, including the Forge cross-check
test:e2e 61/61
fixtures:verify no drift
release:verify passed

Closes slotscope-02a. Unblocks slotscope-xu8 (v1.4), which needs naming
settled before its UI work.

🤖 Generated with Claude Code

A mapping, dynamic array or bytes/string declared inside a struct or an array
element could not be named at all. buildStaticIndex built variableBaseSlots from
layout.storage, which lists top-level entries only, so referenceVariablesBySlot
never saw a nested head, groundHash could not ground keccak(key || headSlot),
and every access to such an entry resolved as unresolved — the product silently
failed to name storage it otherwise understands.

buildStaticIndex already decodes the layout for cellsBySlot, and that model
carries every nested head as a collapsed span with its exact base slot and
dotted path. Index those too.

Verified end to end with a real compiled contract: a write to nest.inner[addr]
inside a struct now resolves exact as `nest.inner[0xaa..]` where it previously
reported unresolved. Two consumers get the same fix for free — string/bytes
migration annotation and the bytes-data chunk labels both look variables up in
the same index, so nested bytes/string heads now annotate correctly as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
slotscope Ready Ready Preview Jul 30, 2026 2:35pm

@halaprix
halaprix merged commit 3ceaf56 into master Jul 30, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant