Skip to content

chore: bump Foundry to 1.8.5 - #25602

Merged
spalladino merged 18 commits into
nextfrom
cb/foundry-1.8.5
Oct 8, 2026
Merged

spalladino merged 18 commits into
nextfrom
cb/foundry-1.8.5

Conversation

@AztecBot

@AztecBot AztecBot commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Moves the pinned Foundry toolchain from 1.4.1 to 1.8.5 (latest release, published 2026-10-05) everywhere the repo pins it, adapts l1-contracts to the behaviour changes shipped in Foundry 1.5 through 1.8, targets the Osaka EVM that mainnet runs, and introduces build image tag 3.1 so this toolchain can be published without disturbing next.

Pins updated:

  • bootstrap.sh (expected_abs_foundry_version, which the toolchain check greps from forge --version / anvil --version)
  • build-images/src/Dockerfile (FOUNDRY_VERSION, the build/devbox image)
  • scripts/setup-container.sh

Adaptations required by the new toolchain

  • forge fmt output changed (Foundry 1.5 formatter). 48 Solidity files under l1-contracts reformatted with forge fmt 1.8.5 so forge fmt --check passes. Every change is whitespace-only: stripping all whitespace from each file before and after yields identical token streams (checked for all 48 files).
  • foundry.toml: isolate = false. Foundry 1.8 runs forge tests with --isolate by default, which executes each top-level call as its own transaction. That charges cold-access and intrinsic gas per call, which pushed the large validator-set tests (RollupGetters, tmnt333, flushEntryQueue fuzz) past the gas limit, and failed the getCurrentEpochCommittee gas-growth assertion. Pinning it off keeps the semantics the suite was written against. It does not affect the committed gas reports: a gas report (FORGE_GAS_REPORT=true) isolates every call whatever this is set to, and the same report is byte-identical with it on or off. Regenerating gas_report.json under 1.8.5 reproduces every committed min/max; only fuzz-driven call counts and averages drift (the 1.5 fuzzer samples inputs differently even with --fuzz-seed 42). gas_benchmark.md regenerated under 1.8.5 is identical to what next produces under 1.4.1, and partial_epoch_proof_gas_report.json reproduces exactly.
  • foundry.toml: evm_version = 'osaka'. Mainnet runs the Osaka EVM (Fusaka activated; the current fork reported by eth_config is the second BPO fork of 2026-01-07, with no next fork scheduled), and Foundry 1.7+ defaults forge and anvil to Osaka. Building with the Osaka target produces byte-identical creation and runtime code for all 125 src/ contracts (solc 0.8.30 emits no Osaka-only opcodes here), the full suite passes, the Rollup gas report matches on every min/max, and nothing in src/ uses the modexp precompile that EIP-7883 reprices. solc 0.8.30 still labels osaka experimental in its help text; it is the chain we deploy to, so the tests should simulate it.
  • foundry.toml: dropped variable_override_spacing. Not a recognised [fmt] key in 1.8.5 (every forge invocation warned about it); override_spacing = false on the next line is the key that is honoured.
  • test/governance/governance/tmnt331.t.sol. Governance__CallerCannotBeSelf() declares no parameters, but the test encoded an address argument into its expectRevert data. Older forge matched that leniently; 1.8.5 compares revert data exactly, so the test now encodes the selector alone.
  • scripts/forge_broadcast.js. forge script 1.8.5 rejects --batch-size (error: unexpected argument '--batch-size' found), which broke scripts/test_rollup_upgrade.sh. The wrapper now passes --slow (send the next tx only after the previous one is confirmed) in the automining-anvil case where it previously used --batch-size 1, and leaves forge's default batching elsewhere. Real-chain deploys therefore no longer send in batches of 8; there is no flag left that reproduces that. If strictly sequential live deploys are preferred, pass --slow unconditionally.
  • l1-contracts/bootstrap.sh build_src and barretenberg/sol/bootstrap.sh build_sol no longer run forge install. Under 1.8.5 forge install syncs every submodule of the repository to foundry.lock and exits 1 when the lock names a revision a shallow clone does not have. Both lock files list l1-contracts/lib/circuits, labs and noir/noir-repo behind the revisions the repository records, so the cache-miss build failed before compiling anything (1.4.1 exits 0 and touches nothing). The git submodule update --init --recursive ./lib that follows already checks the libraries out at the recorded revisions.
  • l1-contracts/bootstrap.sh build_verifier ends with a full forge build. Under 1.8.5, running forge test after an explicit-path forge build so that forge incrementally compiles only the handful of leftover files (shouting.t.sol, test/script/*, scripts) produces inconsistent artifacts: 3 of 3 such runs failed 177 tests with EvmError: Revert at the same ~2.93M gas point in every Rollup-deploying suite. A full build before the artifacts are uploaded means forge test has nothing left to compile; that sequence passed every time.

Build image 3.1

  • build-images/bootstrap.sh version, build-images/run.sh, .devcontainer/dev/devcontainer.json, ci3/bootstrap_ec2, ci3/docker_isolate, ci3/aws/ami_update.sh and ci3/tests/signal_test now reference 3.1. CI runners boot from an AMI with 3.0 already cached and bootstrap_ec2 runs docker run aztecprotocol/devbox:<tag> without pulling first, so a re-pushed 3.0 would never reach them and would break every other PR on next (whose checkout pins 1.4.1). A fresh tag is pulled on first use and leaves next untouched.
  • build-images/bootstrap.sh build_ec2 and ci3/aws/ami_update.sh are ported to the current aws_request_instance contract (state directory, KEY_NAME, aws_terminate_instance <state_dir>); they still called the pre-March-2026 three-argument form and failed with state_dir: unbound variable before doing anything. The port was exercised end to end against stubbed aws, ssh and docker commands: it exits 0, requests and terminates four instances, pushes the manifests and writes both AMI id files, where the scripts as they are on next fail with $4: unbound variable before requesting anything. It has not been run against real AWS.

To go green, the 3.1 images (build, devbox, sysbox, amd64 + arm64 + manifest) must be published to Docker Hub. #25606 adds a workflow that runs this branch's own deploy script; a laptop runbook is in the PR thread as a fallback. Refreshing the AMIs (ci3/aws/ami_update.sh, commit the new ci3/aws/ami_id_*) only speeds up cold starts and can follow later from the CI AWS account. A mainframe admin also needs to point /usr/local/bin/launch_sysbox at sysbox:3.1.

Verified locally with Foundry 1.8.5 binaries

Check Result
forge fmt --check clean
forge build (bootstrap's file set) compiles
forge test (full suite, Osaka target) 1383 passed, 0 failed, 3 skipped (1386)
scripts/test_rollup_upgrade.sh (anvil 1.8.5 + forge script broadcast) completed successfully
scripts/check_contract_sizes.sh (both profiles, Osaka target) within EIP-170
solhint unchanged warnings only
Bytecode, Osaka vs Prague target identical for all 125 src/ contracts (metadata aside)

Things to know

  • forge build now emits ~245 non-fatal forge-lint warnings because 1.8 added many detectors. A stacked PR on this branch brings that to zero without changing bytecode.
  • The existing CI command forge test --match-contract MerkleCheck --ffi matches no contract on next (no MerkleCheck contract exists under test/); this predates the bump and still exits 0.
  • The anvil-related skip of uniswap_trade_on_l1_from_l2.test.ts in .test_patterns.yml is untouched.

Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@AztecBot AztecBot added ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR. labels Oct 6, 2026

@alexghr alexghr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AztecBot

AztecBot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Publishing the 3.1 build image (needed before CI3 can pass): step-by-step runbook, Docker Hub only, no AWS required: https://gist.github.com/AztecBot/8f49f33d121903a38644b3ecd18f67d8

Short version: on the cb/foundry-1.8.5 branch, docker login -u aztecprotocolci, then ./build-images/bootstrap.sh && ./build-images/bootstrap.sh push-images on an arm64 and an amd64 machine (or --platform linux/amd64 under emulation), then ./build-images/bootstrap.sh push-manifests. The AMI refresh (ci3/aws/ami_update.sh) is a cold-start optimisation and can follow later from the CI AWS account; the port of those scripts in this PR is untested for lack of that account.

Stacked lint PR: #25605.


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@AztecBot

AztecBot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Runbook v2 (login step now reads the Docker Hub password from a silent prompt instead of a command line, so it never lands in shell history or a file): https://gist.github.com/AztecBot/9b1b2331855fc1315420fdd9cfc59e1f — supersedes the link in the comment above.


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@spalladino
spalladino marked this pull request as ready for review October 6, 2026 17:35
Comment thread build-images/bootstrap.sh Outdated
sir="${parts[1]}"
iid="${parts[2]}"
trap 'aws_terminate_instance $iid $sir || true' EXIT
local state_dir=$(mktemp -d /tmp/aws_request_instance.XXXXXX)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EXIT trap on the next line is single-quoted, so $state_dir is expanded when the script exits. By then build_ec2 has returned and its local is gone. With set -euo pipefail on, the trap aborts with state_dir: unbound variable before aws_terminate_instance runs, and || true can't catch an expansion error. The failure path does the same, because errexit unwinds the function before the trap fires.

So the instance is never terminated. On success the script also exits 1 instead of 0, which fails build_all under parallel, and deploy never reaches update_manifests or update_amis. Dropping local fixes it:

Suggested change
local state_dir=$(mktemp -d /tmp/aws_request_instance.XXXXXX)
state_dir=$(mktemp -d /tmp/aws_request_instance.XXXXXX)

Written by Claude

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Written by human: I haven't verified the report above

@spalladino

Copy link
Copy Markdown
Contributor

FYI this needs porting to v6 and private

@AztecBot

AztecBot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

@spalladino the review comment on build_ec2 is correct, verified rather than taken on trust: with local state_dir and the single-quoted EXIT trap, a minimal repro under set -euo pipefail exits 1 with state_dir: unbound variable and never calls the terminate helper; without local it exits 0 and terminates. Pushed the one-line fix (76e68aa).

On the v6/private port: added port-to-v6 and private-port-next to this PR and to the stacked lint PR #25605.


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@AztecBot

AztecBot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Publishing the 3.1 build image: use #25606, not the manual runbooks above. The two earlier comments linking a laptop-build runbook are superseded.

#25606 adds a manually dispatched Publish build images workflow that builds build, devbox and sysbox on GitHub-hosted amd64 and arm64 runners and pushes them plus the manifests, using the Docker Hub secrets already stored in the master environment. Nobody needs the password or a local build. Once #25606 is on next:

gh workflow run publish-build-images.yml --repo AztecProtocol/aztec-packages --ref next -f ref=76e68aaa3bfc2c638c84bc48d841f085917854c0

That SHA is the current head of this branch, whose build-images/bootstrap.sh has version="3.1". If build-images/src changes on this branch after 3.1 is published, bump the version (the workflow refuses to overwrite an existing tag). The AMI refresh is still a separate, optional follow-up.


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@AztecBot
AztecBot requested a review from iakovenkos as a code owner October 6, 2026 21:43
@AztecBot

AztecBot commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Review follow-up, pushed as ff9a8bf:

  • forge install dropped from l1-contracts/bootstrap.sh and barretenberg/sol/bootstrap.sh. Under Foundry 1.8.5 it syncs every submodule of the repository to foundry.lock and exits 1 (fatal: reference is not a tree: e47bcd52…) because both lock files list l1-contracts/lib/circuits, labs and noir/noir-repo behind the revisions the repository records. 1.4.1 exits 0 and touches nothing. Reproduced in CI's submodule state (--depth 1 plus the labs patch series), so the cache-miss build would have failed on the first CI run. The git submodule update --init --recursive ./lib that follows already checks the libraries out at the recorded revisions.
  • isolate = false comment corrected. Gas reports isolate every call regardless of the setting (the RollupTest report is byte-identical with it on or off), so the setting only matters for the plain test run; the PR body now says the same.

Checked and unchanged: CI build order on this head (1383 passed, 0 failed, 3 skipped); gas_benchmark.md regenerated under 1.8.5 is identical to what next produces under 1.4.1; partial_epoch_proof_gas_report.json reproduces exactly.

Not verifiable here: the barretenberg/sol tests now run with per-call isolation (its foundry.toml has no isolate setting). Its gas_limit is 9e17 and its benchmark is a gas report, so I expect no effect, but those tests need bb-generated verifiers I cannot build in this session.


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

@iAmMichaelConnor
iAmMichaelConnor added this pull request to stack #25610 October 7, 2026 08:57
@AztecBot

AztecBot commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

CI diagnosis for the 16:02 UTC run on 93fa669 (run 37648918301): the build and 8,064 tests passed; the one failure was single-node/prover/server/full.test.ts with code: 125, and the cause is in its log:

docker: failed to extract layer … /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/… : no space left on device

The isolated test pulls aztecprotocol/build:3.1 (the AMI caches only 3.0) and the devbox's inner Docker stored it under /var/lib/containerd, i.e. the container's ephemeral filesystem rather than the cached /var/lib/docker volume, which filled up. The other RETRYING entries were queued behind the same pull.

That run pulled devbox:3.1 at ~16:04, before the image was republished at 16:15 with "containerd-snapshotter": false in /etc/docker/daemon.json (verified by fetching that layer from the registry). The empty commit 5d4908a only re-triggers CI on the republished image. If the pull into the volume still runs out of space, the remaining fix is refreshing the AMIs so build:3.1 is pre-cached (ci3/aws/ami_update.sh).


Created by claudebox · group: slackbot · requested by Mike (@iAmMichaelConnor) · Slack thread

AztecBot and others added 13 commits October 7, 2026 19:09
…l builds

Foundry 1.8.5's forge install syncs every submodule of the repository to
foundry.lock and exits non-zero when the lock names a revision that a
shallow clone does not have. The lock lists lib/circuits, labs and
noir/noir-repo at revisions behind the ones the repository records, so
the build failed on a cache miss. git submodule update already checks
the libraries out at the recorded revisions.

Also correct the isolate comment: gas reports isolate every call
regardless of the setting, so it has no effect on the committed reports.
The 16:02 UTC run pulled a devbox:3.1 published before the daemon
config disabled the containerd image store, so the inner Docker
extracted build:3.1 outside the cached /var/lib/docker volume and ran
out of disk. The image republished at 16:15 UTC carries the setting.
forge script holds an exclusive lock on the script's recovery state for
the whole broadcast and exits immediately when another forge already
holds it, so two deployments launched from the same project directory
cannot overlap. forge_broadcast.js now serializes them on a lock file in
cache/, reclaiming a lock whose holder has exited.
Carried as labs-patches/0011 until aztec-node takes it. anvil 1.8
returns a transaction's hash before mining it, so clients built without
an explicit polling interval paid viem's 4 s default on every receipt
wait; the l1_publisher integration test went from 102 s to past its
600 s budget. The patch defaults the interval to the 1 s the node's own
clients use and has the jest runners and the e2e compose file set
100 ms.
…tion

Carried as labs-patches/0012. epoch-cache, sequencer-client and cli
tests share the host and all bound anvil to 8545; CI hit the collision
in epoch_cache.integration.test.ts.
Under the osaka EVM target the 32-validator flush in one transaction
falls a few thousand gas short of the per-deposit flush floor at a
16M limit; 2^24 is the largest a single transaction may use.
The build runs forge fmt in barretenberg/sol, which under 1.8.5 rewrote
Relations.sol and CommitmentScheme.sol and left the working tree dirty
and out of sync with honk_contract.hpp and honk_zk_contract.hpp.
Whitespace-only; both templates regenerated with copy_to_cpp.sh.
…ed project

Foundry 1.8 records its remappings as absolute paths in
cache/solidity-files-cache.json and drops the whole cache when they differ
from the project's. The l1-artifacts bundle is copied to a temp directory
before every deploy, so each forge script there recompiled from scratch.

Since the entry queue flush became a second forge script run, that compile
happens after the rollup is deployed. On the interval-mining anvil the tests
use, the chain advances one 12 s block per wall-clock second while solc runs,
so the flush landed ~100 s after genesis instead of ~36 s: past the epoch 3
validator-set sample time (and, on slow runners, past epoch 3 itself), which
broke the epoch cache integration tests.

forge_broadcast.js now rebases the cache's recorded paths onto the directory
it runs in before broadcasting, so the prebuilt artifacts are reused and no
compilation happens.
@AztecBot

AztecBot commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/0ff8c71bde134dc3�0ff8c71bde134dc38;;�): cd labs && export root= ci3= &&  yarn-project/end-to-end/scripts/run_test.sh simple src/multi-node/slashing/attested_invalid_proposal.parallel.test.ts "slashes a lazy attester for an invalid checkpoint and clears it on delayed equivocation" (163s) (code: 0) group:e2e-p2p-epoch-flakes

@charlielye charlielye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ive managed to build this and have pushed the new amis.
if it goes green i guess its good to merge!

@iAmMichaelConnor

Copy link
Copy Markdown
Contributor

@spalladino has reservations about merging it for v6, just in case it causes problems

@just-mitch
just-mitch removed their request for review October 8, 2026 20:16
@spalladino
spalladino merged commit ef8bee3 into next Oct 8, 2026
16 checks passed
@spalladino
spalladino deleted the cb/foundry-1.8.5 branch October 8, 2026 21:06
spalladino added a commit that referenced this pull request Oct 8, 2026
## Summary

Stacked on #25602 (base branch `cb/foundry-1.8.5`). Brings `forge lint`
under Foundry 1.8.5 from 245 warnings to zero in `l1-contracts`, without
changing any deployed bytecode.

| Where | Count before | What this PR does |
| --- | --- | --- |
| `test/` + `script/` (`environment-read-across-mutation`) | 85 | Real
fix: the flagged `block.timestamp` / `block.number` reads in functions
that also `vm.warp` / `vm.roll` now use `vm.getBlockTimestamp()` /
`vm.getBlockNumber()`, which is what the lint asks for (the optimizer
may reuse an environment read across the cheatcode). 84 lines in 33
files. |
| `src/` policy lints (`block-timestamp`, `require-revert-in-loop`,
`calls-loop`, `reentrancy-events`, `missing-zero-check`) | 109 |
Excluded in `foundry.toml` `[lint]`, each with a one-line reason: slot
timing is timestamp-based by design; committee loops check and call per
member on purpose; events are emitted after the calls they describe with
state already settled; the zero-address sites are constructor/governance
wiring. |
| `src/` correctness lints (`unsafe-typecast` 25, `unused-return` 10,
`uninitialized-local` 11, `empty-block` 3, `erc20-unchecked-transfer` 2,
`reentrancy-no-eth`, `encode-packed-collision`, `missing-events-*` 2) |
55 | Reviewed one by one. Every site gets an inline `// forge-lint:
disable-next-item(...)` preceded by a comment stating why it is safe
(bounds, storage width, guard above, intentional truncation). Seven
`uninitialized-local` sites got an explicit `= 0` initialiser where that
is bytecode-neutral; the four in `SlashingProposer` are suppressed
instead because an explicit initialiser there changes the emitted code
by one byte. |

`lint_on_build` stays on, so `forge build` is now quiet.

## Verification (Foundry 1.8.5 binaries)

- `forge lint` / `forge build`: 0 warnings (was 245).
- `forge fmt --check`: clean. All 41 directives are on their own line
(fmt's comment wrapping merges a directive into a preceding long
comment, which silently disables it; two such cases were caught and
fixed).
- **Bytecode:** built the base branch and this branch side by side and
compared the creation and runtime bytecode of all 125 `src/` contracts
byte-by-byte. Outside CBOR metadata hashes (which change with any source
text), there are **no differences**. The lint PR does not alter what
gets deployed.
- `forge test`: 1383 passed, 0 failed, 3 skipped, in six separate full
runs on this tree, including one with the Osaka EVM target the base
branch now uses.
- `solhint`: unchanged.

## Judgement calls for review

- `unused-return` on `approve(...)` (StakingLib ×2, GSE ×2, MultiAdder):
suppressed on the stated assumption that the staking asset is the
protocol's OZ ERC20 (returns true or reverts). If a non-OZ asset is ever
plausible, `forceApprove` is the real fix, at a bytecode cost.
- `encode-packed-collision` in
`SlashingProposer._preparePayloadDataAndAddress`: suppressed because
`validators` and `amounts` are both sized by `actionCount` behind a
fixed 32-byte round prefix, so the packed layout cannot be ambiguous.
Worth a second pair of eyes since it is a hashing site.
- `missing-events-*` (GSE.addRollup, Inbox.markProvenConsumed):
suppressed rather than adding events, to keep bytecode identical. Adding
events is a product decision.


---
*Created by
[claudebox](https://claudebox.work/v2/sessions/f38155cc1541e786/jobs/8)
· group: `slackbot` · requested by Mike (@iAmMichaelConnor) · [Slack
thread](https://aztecfoundation.slack.com/archives/D0B2N7W1WJD/p1791282577517869?thread_ts=1791282577.517869&cid=D0B2N7W1WJD)*

---------

Co-authored-by: Santiago Palladino <santiago@aztec-labs.com>
spalladino added a commit that referenced this pull request Oct 8, 2026
## Summary

Stacked on #25605 (base branch `cb/foundry-1.8.5-lint`). Bumps the
Solidity compiler to 0.8.37 (latest, released 2026-09-10) in every place
the repo pins it:

- `l1-contracts/foundry.toml`: 0.8.30 → 0.8.37 (`solc =
"./solc-0.8.37"`; `bootstrap.sh download_solc` derives the version from
this line and fetches the binary)
- `barretenberg/sol/foundry.toml`, which points at that same binary
- `barretenberg/acir_tests/sol-test` (the solc-js harness that deploys
and runs generated verifiers end to end): `package.json` now pins `solc`
at exactly `0.8.37`, and the workspace `yarn.lock` moves its resolution
from 0.8.28 to 0.8.37

**Unlike the two PRs below it in the stack, this one changes what gets
deployed, slightly.** It should be merged on its own decision by whoever
signs off L1 bytecode, not as tooling hygiene. It deliberately carries
no port labels for that reason.

## Why

- solc 0.8.30 has seven entries in the official known-bugs list; 0.8.37
has none. None of the seven is reachable in this code as written: five
require the IR pipeline (`via_ir` is not set in either project), the
memory `bytes` element `delete` pattern does not occur in
`l1-contracts/src`, and no contract uses a custom storage layout. So
this is not a security fix; it removes the need to re-argue that for
every future change.
- 0.8.31 made Osaka the default EVM target. Under 0.8.30 the
`evm_version = 'osaka'` set by #25602 is labelled experimental.
- 0.8.36 adds the Amsterdam EVM target.
- One compiler version across forge and the solc-js harness means the
verifier tested end to end is compiled by the same compiler as the one
built by forge.

## Effect on compiled output (measured)

`l1-contracts/src`, built with Foundry 1.8.5, Osaka target, optimizer
100 runs, 0.8.30 vs 0.8.37, 86 contracts with runtime code:

| | Result |
| --- | --- |
| Runtime code identical (metadata aside) | 84 of 86 |
| Runtime code changed | `SlasherDeploymentExtLib` (+15 bytes),
`StakingAssetHandler` (mock, +15 bytes) |
| Constructor code changed, runtime identical | `Rollup` (+7),
`RollupCore` (+7), `SlashingProposer` (+15), `GovernanceProposer` (+15),
`TestERC20` (+15), `MockFeeJuicePortal` (+15) |
| `Rollup` runtime size | 24,222 bytes, unchanged (354 below the EIP-170
limit) |
| `ValidatorOperationsExtLib` runtime size | 23,767 bytes, unchanged |

The changed code is the helper that clears storage slots when a
`string`/`bytes` value is written to storage: 0.8.37 emits an extra
bounds check there, consistent with the 0.8.32 fix for array clearing
near the end of storage. `SlasherDeploymentExtLib` changes only because
it embeds `SlashingProposer`'s constructor code. Every contract's
metadata trailer also changes, since it records the compiler version.

`barretenberg/sol`: `BlakeHonkVerifier` and `BlakeHonkZKVerifier`
(compiled against a placeholder verification key, since real keys need a
barretenberg build) are byte-identical apart from the single
compiler-version byte in the trailer: 15,161 and 16,175 bytes of runtime
code, unchanged.

`sol-test` harness: compiling its `HonkTest.sol` together with a real
bb-generated `HonkVerifier` under solc-js 0.8.28 and 0.8.37, with the
harness's own settings (optimizer runs 1, no CBOR metadata, default EVM
target), gives byte-identical creation and runtime code for both
contracts (verifier runtime 16,624 bytes). The harness sets no
`evmVersion`, so its default target moves from Cancun to Osaka with this
compiler; the output does not change.

## Verification (Foundry 1.8.5 + solc 0.8.37)

- `forge test` in `l1-contracts`: 1383 passed, 0 failed, 3 skipped
(1386).
- `forge fmt --check` clean; `forge lint` 0 warnings.
- `scripts/check_contract_sizes.sh`: within EIP-170 on both profiles.
- `scripts/test_rollup_upgrade.sh` (anvil + forge script broadcast):
completed successfully.
- `yarn install --mode=update-lockfile` in `barretenberg/acir_tests`:
the lock diff is the `solc` entry and its `tmp` dependency (0.0.33 →
0.2.6, dropping `os-tmpdir`), nothing else.

Not run locally, left to CI: the `barretenberg/sol` test suite and the
`acir_tests` Solidity flows (both need a barretenberg build for keys and
proofs), the real generated `HonkVerifier` in `l1-contracts`, and the
arm64 svm download of 0.8.37.

## Things to know

- 0.8.37 adds 14 non-fatal compiler warnings in the `src` build. Four
are in this repo: two comparisons of contract-typed variables in
`EmpireBase.sol` (deprecated; fix is an explicit `address(...)` cast)
and two library functions named `at` (`AddressSnapshotLib`,
`StakingQueue`), which is slated to become a keyword. The other ten are
in OpenZeppelin (`at`, `error` identifiers). Left untouched here to keep
this PR to the compiler pin.
- `barretenberg/acir_tests/sol-test/package-lock.json` is removed.
`sol-test` is a yarn workspace of `barretenberg/acir_tests` and resolves
through that directory's `yarn.lock`; nothing in the repo runs `npm
install` or `npm ci` there (searched the acir_tests scripts, the
barretenberg bootstrap, `.github` and `ci3`), and the file had not been
updated since December 2024, so it recorded a solc version (0.8.27) that
no install used.
- The build image does not embed solc, so no image rebuild is needed for
this PR.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/f38155cc1541e786/jobs/25)
· group: `slackbot` · requested by Mike (@iAmMichaelConnor) · [Slack
thread](https://aztecfoundation.slack.com/archives/D0B2N7W1WJD/p1791282577517869?thread_ts=1791282577.517869&cid=D0B2N7W1WJD)*

---------

Co-authored-by: Santiago Palladino <santiago@aztec-labs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR. private-port-next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants