Skip to content

codegen: use LibCodeGen.addressConstantString instead of a local copy - #308

Open
thedavidmeister wants to merge 1 commit into
mainfrom
codegen-dedupe-address-constant
Open

codegen: use LibCodeGen.addressConstantString instead of a local copy#308
thedavidmeister wants to merge 1 commit into
mainfrom
codegen-dedupe-address-constant

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Closes #307

Motivation

script/BuildPointers.sol defined its own addressConstantString for
address constant DEPLOYED_ADDRESS = address(...) while, in the same file,
calling LibCodeGen.bytesConstantString from rain-sol-codegen for the other
generated constants. LibCodeGen already publishes the address emitter, and its
version is strictly more general — parameterised on the comment text and the
constant name instead of hardcoding both.

Changes

  • script/BuildPointers.sol: local addressConstantString deleted;
    buildContractPointers now uses LibCodeGen.addressConstantString(vm, <the same NatSpec>, "DEPLOYED_ADDRESS", deployed).
  • rain-sol-codegen 0.1.0 -> 0.1.3 (foundry.toml, soldeer.lock,
    remappings.txt, the two versioned import prefixes). Required: the pinned
    0.1.0 predates addressConstantString, which first shipped in published
    0.1.2. The now-dangling rain-sol-codegen-0.1.0/ remapping is dropped;
    forge soldeer update adds the new entry but does not remove the stale one.

Why 0.1.3 and not latest

0.1.0 -> 0.1.3 is purely additive in src/lib — it adds
addressConstantString, bytes32ConstantString and LibSnapshot.sol and
changes nothing this repo already calls, so generated output cannot move.

0.1.4 is not a candidate here, and matters more in this repo than in the other
two. It changes LibFs.pathForContract from <name>.pointers.sol to
<name>.sol and rewrites the THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol header emitted into every generated file. Taking it
would rename and rewrite files inside the frozen src/generated/0_1_1/
snapshot, which downstream pins, and would break LibProdDeployV4.sol's
./<tag>/<name>.pointers.sol import paths. That is a separate migration, not a
side effect of deduplicating one function.

Drift check: byte-identical, nothing regenerated

The issue asks whether this repo's private copy had drifted from the shared one.
It had not. Both emit

\n<comment>\naddress constant DEPLOYED_ADDRESS = address(0x…);\n

and the shared function's only extra behaviour is a line-wrap branch that fires
above 120 columns. This line is 88 columns
(17 + 16 ("DEPLOYED_ADDRESS") + 3 (" = ") + 8 ("address(") + 42 + 2 (");")), so
the single-space branch is taken and the bytes match exactly.

Confirmed empirically, not just by reading: forge script ./script/BuildPointers.sol && forge fmt on this branch leaves src/generated/ completely clean — the
12 candidate/ pointer files, LibProdDeployV4.sol and
LibProdDeployCurrent.sol all regenerate to the bytes already committed.

No frozen snapshot is rewritten. deployTag() is the rolling candidate
tag, so the script only ever writes src/generated/candidate/; the frozen
numbered snapshot src/generated/0_1_1/ is read (to emit its aliases into
LibProdDeployV4.sol) and never written. It came through the regeneration
untouched, and CI's frozen-snapshots-append-only check enforces that
independently.

QA

  • Discriminating tests:
    • The repo's own Git is clean workflow, run verbatim locally: forge script ./script/BuildPointers.sol && forge fmt && git diff --exit-code. It is
      discriminating for exactly this change because the committed
      src/generated/candidate/*.pointers.sol were produced by the OLD
      hand-rolled emitter, so any byte the new one emits differently shows up as a
      diff.
    • Baseline run recorded script_rc=0 generated_files_dirty=0 — proof the gate
      actually executed and was green, not merely assumed.
  • Mutations applied:
    • Three mutants on the new call site, one per drift axis the issue names, each
      regenerated and re-checked against the committed artifacts:
    • M1 comment text (deploy address -> deployed address): KILLED,
      generated_files_dirty=12.
    • M2 constant name (DEPLOYED_ADDRESS -> DEPLOYED_ADDR): KILLED,
      generated_files_dirty=12.
    • M3 line wrapping (the comment's internal \n collapsed to a space): KILLED,
      generated_files_dirty=12.
    • 3/3 killed, 0 survived, each mutant reaching all 12 generated contracts. The
      harness aborts if the unmutated baseline does not come back clean, so a
      silently-not-running gate cannot report kills.
  • Oracle:
    • The committed generated artifacts themselves, which are the pre-change
      output of the emitter being replaced. Byte-equality against them is the
      whole correctness claim; it is checked, not reasoned about.
  • Category check:
    • The drift axes are covered as a category, not as three examples: comment
      text, constant name and line wrapping are the complete set of inputs the
      shared function's output depends on, since it is pure over
      (comment, name, address) with one length-derived branch. The address
      itself is covered by the unchanged BYTECODE_HASH/CREATION_CODE/
      RUNTIME_CODE constants generated beside it, and the downstream
      LibProdDeployV4/LibProdDeployCurrent aliases are regenerated in the same
      run. No production Solidity changes in this PR: the only non-script edits
      are the dependency pin, its lock and the remappings it generates, so no
      deployed bytecode and no deterministic address moves.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Updated the code generation tooling to a newer version.
    • Improved generated address constant formatting for build outputs.

script/BuildPointers.sol hand-rolled an address-constant emitter that
rain-sol-codegen already publishes as LibCodeGen.addressConstantString,
in the same file that already calls LibCodeGen.bytesConstantString. The
private copy hardcodes the comment text and the DEPLOYED_ADDRESS name;
the shared one is parameterised on both.

The pinned rain-sol-codegen 0.1.0 predates addressConstantString (it
first shipped in 0.1.2), so the dependency moves to 0.1.3 — the newest
version that leaves generated output byte-identical. 0.1.0 -> 0.1.3 is
purely additive in src/lib (addressConstantString, bytes32ConstantString,
LibSnapshot); 0.1.4 is not, because it renames LibFs.pathForContract's
output from <name>.pointers.sol to <name>.sol and rewrites the generated
header comment, which is a separate migration.

Generated output is unchanged: the local emitter and the shared one
produce the same bytes for this input, so no generated file moves and no
frozen per-tag snapshot is rewritten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Aug 13, 2026
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 34641ca5-07de-40a4-9415-e2dab2516669

📥 Commits

Reviewing files that changed from the base of the PR and between 5d15640 and 7e8c9f9.

⛔ Files ignored due to path filters (1)
  • soldeer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • foundry.toml
  • remappings.txt
  • script/BuildPointers.sol

📝 Walkthrough

Walkthrough

The project updates rain-sol-codegen from 0.1.0 to 0.1.3. BuildPointers removes its local address-constant formatter and uses LibCodeGen.addressConstantString for deployed address generation.

Changes

Codegen emitter update

Layer / File(s) Summary
Upgrade and delegate address generation
foundry.toml, remappings.txt, script/BuildPointers.sol
The project uses rain-sol-codegen 0.1.3. BuildPointers removes its local address formatter and delegates deployed address constant generation to LibCodeGen.addressConstantString.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to 7e8c9

This localized dependency and code-generation cleanup preserves the existing generated output and snapshot behavior, so no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

Suggested reviewers: claude, hardyjosh

Poem

A rabbit hops through codegen bright,
The shared formatter gets it right.
Old helper rests beneath the tree,
New library code writes cleanly.
DEPLOYED_ADDRESS blooms in line.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes replacing the local emitter with LibCodeGen.addressConstantString.
Linked Issues check ✅ Passed The PR replaces the local emitter, passes the required arguments, upgrades the dependency, and preserves generated output as required by issue #307.
Out of Scope Changes check ✅ Passed All changes support issue #307 by updating the codegen dependency, remapping, imports, and emitter implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codegen-dedupe-address-constant

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

BuildPointers hand-rolls an address-constant emitter LibCodeGen already provides

1 participant