🚀 What's New
-
Support for backward / forward LocalExitRoot (LER):
- Backward / forward LocalExitRoot (LER) recovery tool (#1502, #1570): New CLI tool (
tools/backward_forward_let) that allows operators to diagnose and recover from scenarios where the Agglayer or L1 state becomes inconsistent with the L2 Local Exit Root — either by rolling the LER back to a previous valid state (backward) or by advancing it to match the expected state (forward). - See the runbook for full operational guidance and e2e tests.
- Backward / forward LocalExitRoot (LER) recovery tool (#1502, #1570): New CLI tool (
-
Support for remove GlobalExitRoot (GER):
- Remove GlobalExitRoot (GER) recovery tool (#1496, #1563): New CLI tool (
tools/remove_ger) to diagnose and recover from invalid GER injections on L2. The tool classifies affected claims into categories (A, B.1, B.2) and guides operators through interactive recovery steps: freeze bridge, remove the invalid GER, unset/re-set or force-emit claims, and restore the bridge. See the runbook for full operational guidance. - Improved GER scanning (#1563): New
scan-invalid-claimssubcommand that scans L2 claim logs, reconstructs the GER used by each claim, validates it against L1, and reports invalid GERs still tied to active claims. Supports bothDetailedClaimEventand legacyClaimEventlogs.
- Remove GlobalExitRoot (GER) recovery tool (#1496, #1563): New CLI tool (
-
Support Full-node RPC for L1 and L2:
- BridgeSyncer + ClaimSyncer split (#1539, #1554): The bridge syncer has been split into two independent components —
BridgeSyncer(deposits) andClaimSyncer(claims). On first startup, existing claim data is automatically migrated to the new ClaimSyncer DB. - L2NetworkConfig with
InitialLERoverride (#1558): New config section to optionally override the initial Local Exit Root instead of querying it from the RollupManager contract on L1. - See the runbook for full operational guidance
- BridgeSyncer + ClaimSyncer split (#1539, #1554): The bridge syncer has been split into two independent components —
-
Fast synchronization for L1InfoTree and improvement reorg detections:
- Multidownloader reorg detection + L1InfoTree integration (#1462): The L1 multidownloader now supports reorg detection and is enabled by default. It is now integrated with the L1 info tree synchronizer.
-
Treat already-monitored GER tx as expected (#1503): AggOracle no longer errors on GER transactions that are already being tracked, reducing spurious errors in steady state.
-
Unset claims max log range (#1520): Removed the upper bound on the log block range for claim fetching. Calls are now automatically chunked on RPC block-range errors.
-
Adjusted REST timeouts (#1557):
ReadTimeoutandWriteTimeoutincreased from2sto5mto handle slow clients reliably.
⚠️ Breaking Changes
There are no breaking changes. All configuration updates are backward compatible.
📋 Config Updates
📣 All configuration updates are backward compatible. Therefore, there is no need to update any config file
- 🛠️ Config: Two new top-level sections are required:
[ClaimL1Sync]and[ClaimL2Sync]. The[BridgeL1Sync]and[BridgeL2Sync]sections gain two new fields:SyncFromInBridgesandEmbeddedClaimSync. See Configuration Updates below. - 🛠️ Config:
L1Multidownloader.Enableddefaults totrue(wasfalse). Nodes not wanting to run it must explicitly setEnabled = false. - 🛠️ Config:
defaultDBQueryTimeoutincreased from60sto5m, and REST timeouts from2sto5m. - 🛠️ Config: New optional MaxL2BlockRange config field in aggsender
New fields summary:
# New section
[L2NetworkConfig]
# InitialLER = # optional override
[BridgeL1Sync]
# New fields in BridgeL1Sync / BridgeL2Sync
SyncFromInBridges = "auto"
EmbeddedClaimSync = "auto"
[ClaimL1Sync]
DBPath = "{{PathRWData}}/claiml1sync.sqlite"
DBQueryTimeout = "{{BridgeL1Sync.DBQueryTimeout}}"
BlockFinality = "{{BridgeL1Sync.BlockFinality}}"
InitialBlockNum = {{BridgeL1Sync.InitialBlockNum}}
AutoStart = "auto"
BridgeAddr = "{{BridgeL1Sync.BridgeAddr}}"
SyncBlockChunkSize = {{BridgeL1Sync.SyncBlockChunkSize}}
RetryAfterErrorPeriod = "{{BridgeL1Sync.RetryAfterErrorPeriod}}"
MaxRetryAttemptsAfterError = {{BridgeL1Sync.MaxRetryAttemptsAfterError}}
WaitForNewBlocksPeriod = "{{BridgeL1Sync.WaitForNewBlocksPeriod}}"
RequireStorageContentCompatibility = {{BridgeL1Sync.RequireStorageContentCompatibility}}
[BridgeL2Sync]
SyncFromInBridges = "auto"
EmbeddedClaimSync = "auto"
[ClaimL2Sync]
DBPath = "{{PathRWData}}/claiml2sync.sqlite"
DBQueryTimeout = "{{BridgeL2Sync.DBQueryTimeout}}"
BlockFinality = "{{BridgeL2Sync.BlockFinality}}"
InitialBlockNum = {{BridgeL2Sync.InitialBlockNum}}
AutoStart = "auto"
BridgeAddr = "{{BridgeL2Sync.BridgeAddr}}"
SyncBlockChunkSize = {{BridgeL2Sync.SyncBlockChunkSize}}
RetryAfterErrorPeriod = "{{BridgeL2Sync.RetryAfterErrorPeriod}}"
MaxRetryAttemptsAfterError = {{BridgeL2Sync.MaxRetryAttemptsAfterError}}
WaitForNewBlocksPeriod = "{{BridgeL2Sync.WaitForNewBlocksPeriod}}"
RequireStorageContentCompatibility = {{BridgeL2Sync.RequireStorageContentCompatibility}}
# L1Multidownloader now enabled by default + new fields
[L1Multidownloader]
Enabled = true
DeveloperMode = false
PeriodToCheckReorgs = "5s"
🐞 Bug Fixes
- #1469 — Error when 2 GERs are injected in the same block due to missing
block_posdiscriminator in theimported_global_exit_roottable. - #1471 — Config typo
DelayBeetweenCertificatescorrected toDelayBetweenCertificatesinAggSender.TriggerASAP. - #1452 — BridgeSyncer migration conflicts between v0.8.1 and v0.9.0 caused by overlapping migration files.
- #1511 — Validator metrics were not being registered on startup, causing missing observability data.
- #1522 — Error backfilling claims when a single transaction contains multiple bridge events (addresses were read as strings instead of
common.Address). - #1574 — ClaimSyncer determined a wrong starting block on fresh deployments; now resolved by looking up the earliest settled reference.
- #1570 — Fixes to the backward/forward LET tool discovered during e2e testing.
- #1475 — Go bumped to 1.23.7 to address a security vulnerability (GO-2026-4511).
✅ Testing & Validation
- New e2e test setup (#1474) including fake GER generation (#1500) and Remove GER tool e2e tests (#1496).
- Backward/forward LET test cases (#1502, #1570).
📦 Full Changelog
- chore: bump cdk contracts tooling and adjust renames by @Stefan-Ethernal in #1074
- feat: unify all e2e to latest commitid in e2e main branch by @joanestebanr in #1105
- fix: add cleanup step in single chain e2e workflow by @Stefan-Ethernal in #1126
- fix: aggchain params verification by @goran-ethernal in #1122
- fix: determine pre-etrog bridges and encode global indexes differently by @Stefan-Ethernal in #1124
- chore: bump kurtosis cdk and adapt for Fusaka hardfork by @Stefan-Ethernal in #1128
- chore(deps): bump github.com/ethereum/go-ethereum from 1.16.4 to 1.16.5 by @dependabot[bot] in #1134
- feat: turn off
meddlerdebug by @goran-ethernal in #1140 - fix: nightly e2e tests by @Stefan-Ethernal in #1132
- feat: remove calldata from bridge service apis by @rachit77 in #1131
- test: remove fixed gas price when sending tx by @Stefan-Ethernal in #1142
- fix: cherry pick of PR 1145 -
imported-bridge-exitcommitment hash in optimistic mode by @goran-ethernal in #1146 - fix: docker arm image by @tnobayashi in #1151
- refactor: bridge service metrics to prometheus by @Stefan-Ethernal in #1156
- fix: build and push both prod and dev images by @Stefan-Ethernal in #1157
- fix: validate remote validator signatures by @adria0pol in #1144
- feat: add test that updates
aggsendercommittee by @goran-ethernal in #1150 - fix: populate version metadata in Docker image by @Stefan-Ethernal in #1163
- feat: removed Common.NetworkID field by @joanestebanr in #1165
- feat: Add tests for L1 reorg detector in bridge syncer by @rachit77 in #1120
- chore(deps): bump github.com/consensys/gnark-crypto from 0.18.0 to 0.18.1 by @dependabot[bot] in #1172
- feat: introduce aggoracle metrics by @Stefan-Ethernal in #1187
- feat: run the l1 info tree syncer with
safeblock finality by @Stefan-Ethernal in #1148 - feat: categorize aggsender metrics to namespaces by @Stefan-Ethernal in #1240
- feat: remove ger, unset claims by @temaniarpit27 in #883
- refactor: change log level by @rachit77 in #1242
- fix: disable
syncFullClaimsfor L1 bridge syncer by @Stefan-Ethernal in #1241 - feat: add a subscription feature in the bridge syncer by @goran-ethernal in #1214
- feat: validate positive offset in block finality by @rachit77 in #1199
- refactor: bridge service metrics by @Stefan-Ethernal in #1238
- chore: reuse
common.HashLengthinstead of magic number by @Stefan-Ethernal in #1253 - chore: increase code coverage in bridge service by @Stefan-Ethernal in #1256
- feat: check always last cert using the initial check by @joanestebanr in #1262
- feat: Add L1 contract fallback check for missing GERs during L2GERSync by @rachit77 in #1265
- feat:
PreconfPPmode, and certificate send trigger separation by @goran-ethernal in #1237 - fix: reintroduce polygonbridgeaddr by @temaniarpit27 in #1271
- fix: address comments by @rachit77 in #1274
- feat: cut certificate size if there are non-finalized GERs (claims) by @goran-ethernal in #1264
- feat: add ValidateGER function to aggsender validator proto def by @Stefan-Ethernal in #1266
- fix: run all tests by @temaniarpit27 in #1273
- feat: add index by @temaniarpit27 in #1280
- chore(deps): bump github.com/ethereum/go-ethereum from 1.16.5 to 1.16.7 by @dependabot[bot] in #1285
- chore(deps): bump golang.org/x/sync from 0.17.0 to 0.18.0 by @dependabot[bot] in #1286
- feat: sync
DetailedClaimEventin bridge syncer by @Stefan-Ethernal in #1263 - feat: remove caller address from claims by @Stefan-Ethernal in #1294
- fix: handle reorg detection edgecase (#1298) by @temaniarpit27 in #1303
- feat: pick fixes from zkevm_migration_support-0_7_X (#1304) by @joanestebanr in #1307
- feat: multidownloader safe synchronizations by @joanestebanr in #1234
- feat: update
zkevm-eth-txmanagerreference by @goran-ethernal in #1328 - chore(deps): bump go.uber.org/zap from 1.27.0 to 1.27.1 by @dependabot[bot] in #1321
- fix: remove multilingual tag from mdbook config by @Stefan-Ethernal in #1331
- chore(deps): bump github.com/jmoiron/sqlx from 1.2.0 to 1.4.0 by @dependabot[bot] in #1325
- chore(deps): bump google.golang.org/grpc from 1.76.0 to 1.77.0 by @dependabot[bot] in #1326
- docs: add AGENTS.md for build, style, structure by @vcastellm in #1332
- fix: mdbook config for alerts preprocessor by @Stefan-Ethernal in #1343
- feat: moved PR #1339 from 0.7 to develop. It fixes #1329 and #1345 by @joanestebanr in #1355
- feat: [FEATURE] inject non finalized GERs by @temaniarpit27 in #1305
- fix: release.yml by @temaniarpit27 in #1369
- fix: update ref by @temaniarpit27 in #1370
- fix: update kurtosis ref by @rachit77 in #1373
- chore: bump e2e tests and set the execute-all-tests param by @Stefan-Ethernal in #1363
- fix: disable fail fast in nightlies by @Stefan-Ethernal in #1377
- fix: replace ethClient.BlockByNumber by ethClient.HeaderByNumber by @tnobayashi in #1385
- fix: handle block range too large rpc error, and do chunk calls (cherry-pick of #1387) by @goran-ethernal in #1390
- feat: decrease e2e wait time by @rachit77 in #1374
- fix: From field for bridge event syncronization by @joanestebanr in #1372
- feat: add set claims endpoint by @rachit77 in #1371
- chore(deps): bump github.com/quic-go/quic-go from 0.54.1 to 0.57.0 by @dependabot[bot] in #1393
- fix: claims count logic after compaction logic by @rachit77 in #1395
- fix: update ref by @temaniarpit27 in #1406
- feat: add
to_addressfiled in bridge api response by @rachit77 in #1405 - fix: block range error parsing (exceeded maximum block range:) by @joanestebanr in #1413
- feat: update ref by @temaniarpit27 in #1415
- chore(deps): bump golang.org/x/sync from 0.18.0 to 0.19.0 by @dependabot[bot] in #1384
- chore(deps): bump google.golang.org/protobuf from 1.36.10 to 1.36.11 by @dependabot[bot] in #1399
- feat: update config by @temaniarpit27 in #1416
- feat: streamline running e2e testing locally by @vcastellm in #1333
- fix: typo in certificate function names by @vcastellm in #1424
- fix: check InError certs when no pending certs by @vcastellm in #1425
- chore(deps): bump google.golang.org/grpc from 1.77.0 to 1.78.0 by @dependabot[bot] in #1438
- fix: preserve retro compatibility of claim events indexing (cherry-pick) by @Stefan-Ethernal in #1441
- feat: index
BackwardLETevent by @Stefan-Ethernal in #1379 - feat: index and handle
forwardLETevent by @goran-ethernal in #1404 - ci: update kurtosis configs by @leovct in #1451
- feat: hash from rpc instead of calculated v2 1389 by @joanestebanr in #1397
- feat: allow to configure the finality to use for l1infotree by @joanestebanr in #1417
- feat: aggsender: send a new certificate as soon latest is settled by @joanestebanr in #1457
- feat: claude code by @joanestebanr in #1463
- feat: implement bridge service client by @arnaubennassar in #1465
- fix: #1468-Error if there are 2 injected GER in the same block by @joanestebanr in #1469
- fix: typo AggSender.TriggerASAP.DelayBeetweenCertificates by @joanestebanr in #1471
- chore: bump go to 1.25.7 (fix vulnerability) by @joanestebanr in #1475
- feat: multidownloader reorg + integration l1infotree by @joanestebanr in #1462
- chore: skip claude if dependabot by @joanestebanr in #1488
- chore(deps): bump google.golang.org/grpc from 1.78.0 to 1.79.1 by @dependabot[bot] in #1487
- chore(deps): bump github.com/mattn/go-sqlite3 from 1.14.32 to 1.14.34 by @dependabot[bot] in #1486
- chore(deps): bump github.com/knadh/koanf/v2 from 2.3.0 to 2.3.2 by @dependabot[bot] in #1464
- feat: new e2e setup by @arnaubennassar in #1474
- feat: add param SyncFromInBridges to bridgesyncer by @joanestebanr in #1485
- chore(deps): bump github.com/ethereum/go-ethereum from 1.16.8 to 1.17.0 by @dependabot[bot] in #1491
- feat: test remove GER tool by @arnaubennassar in #1496
- fix: bridesyncer migration conflicts between v0.8.1 and v0.9.0/develop by @rachit77 in #1452
- feat: Treat already-monitored GER tx as expected #1490 by @joanestebanr in #1503
- fix: expose metrics for validator by @joanestebanr in #1511
- chore(deps): bump github.com/gin-gonic/gin from 1.11.0 to 1.12.0 by @dependabot[bot] in #1506
- feat: fake ger gen by @arnaubennassar in #1500
- feat: unset claims max log range by @arnaubennassar in #1520
- fix: cherry-pick 1515 to develop: Error backfilling in case of same tx have multiples bridges by @joanestebanr in #1522
- fix: update CI workflow configurations by @joanestebanr in #1528
- feat: backward and forward LET testing + runbook + tool by @arnaubennassar in #1502
- feat: split bridgesyncer into bridgesyncer + claimsyncer by @joanestebanr in #1539
- feat: migrate bridgesync claim data into claimsync DB on startup by @joanestebanr in #1554
- feat: add L2NetworkConfig with optional InitialLER override by @joanestebanr in #1558
- feat: adjust REST timeouts by @joanestebanr in #1557
- chore(deps): bump github.com/knadh/koanf/v2 from 2.3.2 to 2.3.4 by @dependabot[bot] in #1553
- chore(deps): bump google.golang.org/grpc from 1.79.1 to 1.79.3 by @dependabot[bot] in #1552
- chore(deps): bump github.com/mattn/go-sqlite3 from 1.14.34 to 1.14.37 by @dependabot[bot] in #1551
- chore(deps): bump golang.org/x/sync from 0.19.0 to 0.20.0 by @dependabot[bot] in #1530
- chore(deps): bump github.com/0xPolygon/cdk-contracts-tooling from 0.0.12 to 0.0.13 by @dependabot[bot] in #1445
- chore(deps): bump github.com/ethereum/go-ethereum from 1.17.0 to 1.17.1 by @dependabot[bot] in #1531
- chore: remove dead code identified by static analysis by @joanestebanr in #1571
- docs: add full node usage guide by @joanestebanr in #1572
- chore(deps): bump github.com/buger/jsonparser from 1.1.1 to 1.1.2 by @dependabot[bot] in #1575
- chore(deps): bump github.com/pelletier/go-toml/v2 from 2.2.4 to 2.3.0 by @dependabot[bot] in #1580
- chore(deps): bump github.com/ethereum/go-ethereum from 1.17.1 to 1.17.2 by @dependabot[bot] in #1579
- chore(deps): bump google.golang.org/grpc from 1.79.3 to 1.80.0 by @dependabot[bot] in #1578
- refactor(aggsender): unify block range adjustment by @arnaubennassar in #1573
- fix: determine claim syncer starting block from earliest settled reference when DB is empty by @joanestebanr in #1574
- feat: Imporve Remove GER tool by @arnaubennassar in #1563
- fix: backward-forward-let by @arnaubennassar in #1570
- fix: add query exceeds max block range to ParseMaxRangeFromError by @joanestebanr in #1589
- feat: configurable batch block header retrieval via RPCClientConfig by @joanestebanr in #1601
- fix: avoid spurious error log when block range is too large in l2gersync by @joanestebanr in #1607
- fix: debug trace bridge call matching by @arnaubennassar in #1609
- fix: embed version info in Docker builds by @joanestebanr in #1619
- fix: include .git in Docker build context for version embedding by @joanestebanr in #1621
- fix: validate legacy checkpoint block against L1 in CheckValidBlock (#1638) by @joanestebanr in #1639
- fix(ci): cherry-pick -dev images for release candidates and -no_shell aliases (#1674) by @joanestebanr in #1685
- cherry-pick: aggsender block range control to release/0.10 by @arnaubennassar in #1686
- fix(aggsender): rebuild FEP cert from scratch on reorged l1inforoot (cherry-pick #1709) by @arnaubennassar in #1712
New Contributors
- @tnobayashi made their first contribution in #1151
- @adria0pol made their first contribution in #1144
- @leovct made their first contribution in #1451
Full Changelog: v0.7.0...v0.10.0