🚀 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.
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
- 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
Full Changelog: v0.9.0-rc3...v0.10.0-rc1