๐ What's New
bridgetrackercomponent + newaggkit-proxyservice (#1740, #1758): A supervised bridge-status tracker that resolves a bridge's full lifecycle from its creation tx โ now covering all three directions (L1โL2, L2โL1, L2โL2) โ exposed via REST + WebSocket endpoints on a newaggkit-proxybinary. Tracks throughBridgeEventemission, LER update, certificate inclusion/settlement, L1-settlement confirmation, GER injection and claim, backed by an in-memory registry and step engine, with Swagger/OpenAPI docs served at/tracker/v1/swaggerand a newdocs/bridgetracker.md.- โ ๏ธ Ships breaking config changes โ see Breaking Changes below.
- Auto Claim: L2โL1 and L2โL2 support (#1705): Extends Auto Claim (L1โL2 only since
v0.11.0-rc1) to the other two bridge directions. A newL2ToLxbridge detector watches each source rollup's local exit root advancing and fetches new bridges from that rollup's own bridge service; GER-injection readiness for any L2-destination claimer is now gated by calling the destination network's own bridge service instead of running a per-claimerl2gersync(removed entirely โ no more per-claimer SQLite DB, reorg detector, or dedicated L2 RPC client). An L1-destination (NetworkID = 0) claimer is now a fully-supported configuration.- โ ๏ธ Ships breaking config, API and storage changes โ see Breaking Changes below.
- New
op-pp-2chainse2e environment (#1691): Two OP-PP L2 chains on a shared L1/agglayer instance, with a newTestBridgeL2ToL2covering the full L2โL2 flow end to end; the CI e2e matrix now runs bothop-ppandop-pp-2chains.
โ ๏ธ Breaking Changes
- ๐ ๏ธ Config:
[Tracker].BlockFinality(proxy config) splits intoL1BlockFinality/L2BlockFinality; addsRegisterResolveTimeout(#1758). - ๐ ๏ธ Config:
bridgeservicefinder.Config's static bridge-service override map renamesURLsโBridgeURLs, to make room for a newRPCURLsoverride map (#1740). Affects[AutoClaim.BridgeServiceFinder.URLs]โ[AutoClaim.BridgeServiceFinder.BridgeURLs]; Viper silently ignores unknown keys, so a config left on the old key ends up with an empty override map. - ๐ ๏ธ Config:
bridgeservicefinder.DefaultHealthCheckPathdefault changes/healthโ/, matching where the bridge service actually registers its health handler (#1758). - ๐ ๏ธ Config:
[AutoClaim.L2ToLxBridgeDetector]is no longer a disabled placeholder โ it's a real, independently-enableable detector. A new[AutoClaim.BridgeServiceFinder]section is now required when it's enabled, or when any enabled claimer (either direction) has an L2 destination โ including a pure L1โL2 setup with the detector disabled (#1705). - ๐ ๏ธ Config:
RetryAfterErrorPeriod/MaxRetryAttemptsAfterErrorremoved from both[AutoClaim.L1ToL2BridgeDetector]and[AutoClaim.L2ToLxBridgeDetector]โ they were validated but never consumed (#1705). - ๐ ๏ธ Config: Per-claimer
[[AutoClaim.Claimers]].BlockFinality/.InitialBlockNumremoved โ they configured the now-deleted per-claimerl2gersync(#1705). - โ๏ธ Operational: L1โL2 auto claiming now requires
[AutoClaim.BridgeServiceFinder](withRollupManagerAddr) and the destination network's own bridge service to be reachable, whenever the destination is an L2 โ previously it only needed the shared[L2GERSync]/[ReorgDetectorL2]settings (#1705). - ๐ API: New binary
aggkit-proxy; new bridge-service endpointsGET /bridge/v1/root-by-ler(#1758) andGET /bridge/v1/claim-candidates(#1705). - ๐ API:
GET /bridge/v1/injected-l1-info-leafnow returns404 Not Found(previously500 Internal Server Error) when no GER covers the requested L1 info tree index yet; the Go client surfaces this asclient.ErrNotFound(#1705). - ๐ API: Auto Claim request IDs (
GET /autoclaim/v1/bridges/{id}) change format fromorigin_network:destination_network:deposit_counttosource_network:destination_network:deposit_countโ numerically identical for every pre-existing L1โL2 request (#1705). - ๐๏ธ Storage:
autoclaim_requestgainssource_network,ler,verify_block_numcolumns and its uniqueness constraint moves to(source_network, destination_network, deposit_count); newautoclaim_ler_cursortable (migrationautoclaim0002.sql, safe โautoclaim0001has not shipped in any tagged release) (#1705). - No breaking changes from #1769, #1761, #1732, #1760, #1691, #1743.
๐ Configuration Updates
- ๐งพ Config Diff:
v0.11.0-rc2...v0.11.0-rc3โ seeproxy/config/default.go,autoclaim/config/config.go,bridgeservicefinder/config.go.
New [Tracker] proxy-config section:
[Tracker]
RetentionPeriod = "10m"
RegisterResolveTimeout = "3s"
L1BlockFinality = "LatestBlock"
L2BlockFinality = "LatestBlock"
MaxTrackedBridges = 100000Renamed bridge-service-finder override key:
[AutoClaim.BridgeServiceFinder]
RollupManagerAddr = "0x..."
-[AutoClaim.BridgeServiceFinder.URLs]
+[AutoClaim.BridgeServiceFinder.BridgeURLs]
0 = "http://l1-bridge-service:5577"New [AutoClaim.L2ToLxBridgeDetector] (real, and [AutoClaim.BridgeServiceFinder] now required alongside it):
[AutoClaim.L2ToLxBridgeDetector]
Enabled = true
StartL1Block = 0 # 0 = full history
PollInterval = "3s"
[AutoClaim.BridgeServiceFinder]
RollupManagerAddr = "0x..." # required when L2ToLxBridgeDetector.Enabled = true, OR when any
# enabled claimer (either direction) has an L2 destination
PollInterval = "30s"
[AutoClaim.BridgeServiceFinder.BridgeURLs]
# Required to reach network 0 (L1), which is never enumerated on-chain:
0 = "http://static-override-l1:5577"
# Per-claimer BlockFinality/InitialBlockNum no longer exist โ an L2-destination
# claimer's readiness gate now comes from AutoClaim.BridgeServiceFinder + the
# destination's own bridge service instead.
[[AutoClaim.Claimers]]
Enabled = true
NetworkID = 0 # now a legal L1-destination claimer (requires L2ToLxBridgeDetector.Enabled)
...Full reference: docs/autoclaim.md and docs/bridgetracker/README.md.
๐ Bug Fixes
- #1769 โ
force_ger_updatesent a real forced update only once, ever. EverySendForcedGERUpdatecall packs byte-for-byte identical calldata, andethtxmanager.Addderives its monitored-tx id purely from(to, value, data)โ so every call after the first collided withErrAlreadyExistsand just re-observed that same (already-terminal) tx forever, instead of ever broadcasting a new one. In practice the GER never updated again after the first forced send, and every later trigger (including on every restart, since the boot scan always found the GER still genuinely stale) looked like a send but was really a stuck no-op. Fixed by removing the tx from the monitoring DB once it reaches a terminal status. - #1761 โ Auto Claim's
proofReadyForRequestcompared an L1 block number againstBridge.BlockNum, which for L2-origin requests is the source L2's own block number โ an incomparable-units bug that left the readiness gate permanently closed once the source L2's height exceeded L1's (common on fast-block devnets), stalling requests indefinitely (observed even after L1 was manually advanced 700+ blocks). Now compares againstVerifyBlockNumfor L2-origin requests, the same L1-block quantity the proof itself uses. - #1732 โ
l2gersyncnever recovered automatically after an invalid GER was removed on-chain. The removal check was gated behindIsUpToDateand never converged, so the syncer retried forever (or crash-looped under a non-negativeMaxRetryAttemptsAfterError). Now decoupled fromIsUpToDate: each retry re-checks removal at latest and only skips the invalid insert once a genuine on-chain removal event is observed and the GER map entry is zeroed โ never fatal for this class of error.GET /bridge/v1/sync-statusgains an additivel2_ger_infoobject for external visibility. - #1760 โ AggSender stopped creating certificates beyond the last claim/bridge block on chains whose
finalizedtag lags or never advances (some local devnets): the classicsyncdownloader only persisted progress past the reorg detector's finalized block when it either caught up or found an event, so with no new events it looped forever without reporting a block, pinningGetLastProcessedBlockto the last block that had one. Fixed by reporting the swept-to block as an (unfinalized) empty block once the chain head is reached, same as the existing "has events" path.
โ Testing & Validation
bridgetracker/aggkit-proxy(#1740, #1758): unit coverage acrossbridgetracker/...,bridgeservice/...,proxy/...; new e2eTestBridgeTrackerL1ToL2in theop-pp-2chainsCI matrix group.- Auto Claim L2โL1/L2โL2 (#1705): unit coverage across every touched/added package (60โ100% per package); dockerized e2e on
op-pp(TestAutoClaimL2ToL1AllowAll, new L2โL1 direction end to end) andop-pp-2chains(TestAutoClaimL2ToL2AllowAll, run twice consecutively). force_ger_update(#1769): new regression test driving two full send cycles back-to-back asserting the second gets a freshAdd, plus a new integration test covering the flip side of the existing cold-start test โ booting with a genuinely fresh GER must not force a spurious send.autoclaimL2-origin readiness (#1761): new unit tests plus in-enclave verification on a kurtosis-cdk 2-L2 devnet (previously-stuck L2-1โL2-2 deposit now auto-claims in ~2m11s).l2gersyncrecovery (#1732): unit coverage for the non-fatal retry path; the 5 previously-skipped remove-GER e2e tests re-enabled, split across three CI matrix groups onop-pp.syncdownloader fix (#1760): updatedTestDownloadBeforeFinalizedto assert progress is reported at the chain tip even with no events; reproduced the original stall against a local Kurtosis OP-PP environment.op-pp-2chainsenv (#1691): newTestBridgeL2ToL2, bothop-ppandop-pp-2chainsCI matrix jobs green.
๐ง Maintenance & Dependencies
exit_certificatesecurity report updated to v2.1 (#1743): Sigma Prime's audit report adds one new low-severity finding from their review of the state-dump completeness fix (#1729, already inv0.11.0-rc1).
๐ฆ Full Changelog
- feat: add op-pp-2chains env and L2โL2 bridge test by @arnaubennassar in #1691
- feat: auto claim L2->L1 and L2->L2 support by @arnaubennassar in #1705
- fix(l1infotreesync): recover from undetected L1 tip reorg instead of halting permanently by @joanestebanr in #1738 (content-identical to the cherry-pick already shipped in
v0.11.0-rc2; appears here only becausev0.11.0-rc3is cut fromdeveloprather thanrelease/0.11) - chore(exit_certificate): update Sigma Prime security assessment report to v2.1 by @joanestebanr in #1743
- feat(bridgetracker): add bridge tracking endpoints, L1->L2, and proxy service by @joanestebanr in #1740
- fix(sync): Aggsender does not create certificates beyond the last claim block by @joanestebanr in #1760
- fix(l2gersync): recover automatically when an invalid GER is removed on-chain by @arnaubennassar in #1732
- feat(bridgetracker,proxy): add bridge status tracker with L2/Lx lifecycle tracking and REST/WS API by @joanestebanr in #1758
- fix(autoclaim): use VerifyBlockNum instead of Bridge.BlockNum for L2-origin proof readiness by @arnaubennassar in #1761
- fix(force_ger_update): forget completed tx so repeat sends are not deduped forever by @arnaubennassar in #1769
Full Changelog: v0.11.0-rc2...v0.11.0-rc3