Repository navigation
v0.11.0
The notes below are written relative to v0.10.1
π What's New
-
aggkit-proxyservice. The proxy serves everything on a single REST server; which routes are available depends on the components it runs (proxy,tracker): -
Bridge service: new
GET /bridge/v1/config(sanitized public config, #1828) andGET /bridge/v1/root-by-ler(#1758);/healthnow reports per-source sync status and/sync-statuscovers all six syncers withis_halted(#1854, #1877). -
New tool:
exit_certificate(+exit_certificate_claimer) (#1582): generates, signs and submits an agglayerCertificatefor an aggchain exiting the Agglayer ecosystem, plus a companion service to claim the resulting exits on L1. -
New tool:
force_ger_update(#1730, #1769, #1778): guarantees the L1 Global Exit Root is updated at least every configurableX, bounding certificate stalls for OP-FEP / DA provability. -
eth_getLogscompleteness verification +l1infotreesyncself-healing (#1773, #1738): a block whose logs bloom is positive for a queried address but whoseeth_getLogsresponse has no matching entry is now flagged and re-queried by block hash.l1infotreesyncpersists a last verified checkpoint and escalates repeated reorgs at the same block to it, turning a permanent stuck-halt into an automatic recovery. -
Per-certificate L2 block range cap: new optional
MaxL2BlockRange(#1673). -
Configurable gRPC client
MaxDecodingMessageSize(#1900): default raised from 4 MiB to 16 MiB; fixesdecoded message length too largewhen requesting aggchain proofs. -
Independent L1 finality knobs (#1849):
L1InfoTreeSync.Finality()no longer returns the multidownloader'sBlockFinality, so valid mixed-finality configs are no longer rejected by the aggsender startup guard. -
Configurable batch block header retrieval (#1606): new
BatchBlockHeaderRetrieval(defaulttrue) for nodes without batch RPC support. -
Improved Backward/Forward LET tooling (#1616) and a new
bridgeservicefinderpackage (#1692, #1810, #1855) that resolves the bridge-service URL of every network attached to a rollup manager. -
Proxy / bridgetracker RPC clients take the block hash from the RPC response (
HashFromJSON = true, #1897), so Glamsterdam block hashes are no longer recomputed from the RLP header. (go-ethereum v1.17.7, which Glamsterdam requires, already shipped in v0.10.1.) -
Docs:
docs/usage_ethereum_full_node.mdnow states that aggkit needs logs (receipts) available from genesis (e.g.reth --full --prune.receipts.before=0).
β οΈ Breaking Changes
Config
[REST]is split into[PublicREST]and[AdminREST](#1662). Existing configs must rename[REST]to[PublicREST]; there is no automatic migration. A leftover[REST]section is ignored and logs a deprecation warning at startup.MaxRequestsPerIPAndSeconddefault changes from10to0(unlimited) in[PublicREST],[AdminREST]and the proxy[REST]β the limit was never enforced there.[RPC]keeps10and is enforced (#1784).CacheConfig(agglayer client) gains six per-method fields (cached/passthrough/forbidden).Cached = truealone no longer impliesGetCertificateHeadercaching: configs that rely on it must opt each method in explicitly (#1771).- The AggOracle
EthTxManagerdefaults used wrong TOML keys and never applied. They are nowWaitReceiptMaxTime/WaitReceiptCheckInterval(wereGetReceiptMaxTime/GetReceiptWaitInterval) (#1875). - gRPC clients: default receive limit goes from 4 MiB to 16 MiB (#1900).
Bridge service API
GET /bridge/v1/l1-info-tree-index,GET /bridge/v1/claim-proofand the L1 path ofGET /bridge/v1/injected-l1-info-leafnow return 404 (not indexed yet β retry later) or 503 (syncer halted / inconsistent) instead of 500. The Go client returnsErrNotFoundon 404 (#1794, #1705).GET /bridge/v1/sync-statusalways answers 200; component failures are reported in each entry'serrorfield instead of a 500 (#1877).global_indexinGET /bridge/v1/bridgesis now emitted as a JSON string (was a bare number that lost precision in JavaScript for L1-origin deposits) (#1835).
Operational / storage
l1infotreesync: on a DB with pre-existing committed-state divergence, the first reorg escalation purges back toInitialBlock(a full automatic resync) instead of halting forever.multidownloaderStepSafenow fetches headers for every block of a queried range β more RPC load during initial sync / catch-up only (#1773).- New DB migrations, applied automatically on startup:
l1infotreesync0005,claimsync0002,bridgesync0016.
π Configuration Updates
Config diff: v0.10.1...v0.11.0 β see config/config.go, config/default.go and proxy/config/default.go.
Required rename (aggkit):
# Before # After
# [REST] [PublicREST]
[PublicREST]
Host = "0.0.0.0"
Port = 5577
ReadTimeout = "5m"
WriteTimeout = "5m"
MaxRequestsPerIPAndSecond = 0New optional fields (aggkit):
[AggSender]
MaxL2BlockRange = 0 # 0 = unlimited (default)
[Validator]
MaxL2BlockRange = "{{AggSender.MaxL2BlockRange}}"
# In [L1NetworkConfig.RPC] and [Common.L2RPC]
BatchBlockHeaderRetrieval = true
# In every gRPC client section ([AggSender.AgglayerClient.GRPC], [AggSender.AggkitProverClient],
# [AggSender.ValidatorClient], [AggchainProofGen.AggkitProverClient], [Validator.AgglayerClient.GRPC])
MaxDecodingMessageSize = 16777216 # 16 MiB; 0 = gRPC default (4 MiB)
# AggOracle EthTxManager: renamed keys
[AggOracle.EVMSender.EthTxManager]
WaitReceiptMaxTime = "250ms" # was GetReceiptMaxTime
WaitReceiptCheckInterval = "1s" # was GetReceiptWaitIntervalAgglayer client cache β each client must now opt methods in explicitly (shown with the previous AggSender behavior):
[AggSender.AgglayerClient.ConfigurationCache]
TTL = "5m"
Capacity = 100
SendCertificate = "passthrough"
GetCertificateHeader = "cached"
GetEpochConfiguration = "passthrough"
GetLatestSettledCertificateHeader = "passthrough"
GetLatestPendingCertificateHeader = "passthrough"
GetNetworkInfo = "passthrough"aggkit-proxy β see proxy/config/default.go for the full defaults. Highlights:
[Tracker]
L1GlobalExitRootAddress = "0x..." # required when running the tracker
L1BlockFinality = "LatestBlock"
L2BlockFinality = "LatestBlock"
DBPath = "" # optional SQLite cache; empty = in-memory
IdleTimeout = "30m"
MaxConcurrentResolutions = 50
[Tracker.ActivitySourceRPC] # optional RPC fallback for recent bridges
Enabled = true
RangeFromBlock = "LatestBlock/-90"
RangeToBlock = "LatestBlock"
[Prometheus]
Enabled = true
Host = "localhost"
Port = 9091
[L2RPC] # applied to every L2 client resolved by the finder
Mode = "basic"
HashFromJSON = true
BatchBlockHeaderRetrieval = trueStandalone tools have their own config files and do not touch the aggkit config: force_ger_update ([ForceGERUpdate], see tools/force_ger_update/example-config.toml) and exit_certificate (JSON or TOML, see the tool README).
π API Updates
π Bridge service API
-
π Bridge service API Update: No breaking interface change β no endpoint removed, no parameter added or removed on existing endpoints, and all changes to existing response bodies are additive. One behavioural change on
/and/sync-status(below).Added endpoints (all
GET):/configβ sanitized public view of the bridge-service config (component sync parameters and contract addresses, deduplicated by network). Never exposes RPC URLs, DB paths or keys./healthβ health status, version and summary bridge sync status. Always responds 200; sync health is reported insync_status/details./l1-info-tree-leaf-by-ger?network_id=0&global_exit_root=β L1 info tree leaf for a given Global Exit Root (network_idmust be 0)./root-by-ler?network_id=&ler=β deposit-count index a local exit root had in the network's local exit tree./settlements?page_number=&page_size=β paginated L1 settlement history (new local exit roots) for the network, most recent first.
Modified endpoints:
/and/sync-statusno longer return500; they always return200and report per-syncer failures in the newerrorfield./response now also includessync_statusanddetails./sync-statusresponse: new optionall2_ger_info,l1_info_tree_info,claim_l1_info,claim_l2_info;NetworkSyncInfogainsis_haltedanderror./claim-proof,/l1-info-tree-index,/injected-l1-info-leaf: now document404(not indexed by the syncers yet, retry later) and503(syncer unavailable or resolving a reorg)./injected-l1-info-leafresponse: new optionalinjected_l2_block_numandinjected_l2_block_timestamp.
Removed endpoints: none.
π Proxy API
-
π AProxy API Update:
aggkit-proxy(bridge tracker, base path/tracker/v1) is new in this version (not present inv0.10.1), so there is no breaking change relative to the previous release. Endpoints (allGET):/tracker/v1/health/tracker/v1/bridge-addressand/tracker/v1/bridge-address/{network_id}/tracker/v1/activity/from/{from_address}(paginated)/tracker/v1/network/{network_id}/tx/{tx_hash}/tracker/v1/network/{network_id}/tx/{tx_hash}/ws(WebSocket, live status updates)
Full reference:
docs/bridgetracker/API.mdanddocs/bridgetracker/REFERENCE_API.md.
π Others API
- π Others API Update: No changes. No
.proto/gRPC interface changes in this version.
π Bug Fixes
- FEP certificates were retried forever after an L1 info root reorg: the
InErrorretry path now validates the certificate's L1 info tree data and rebuilds from scratch when stale (#1709). l1infotreesyncstuck after upgrading from the legacy syncer (e.g. 0.8.x) to the multidownloader:CheckValidBlocknow validates finalized checkpoint blocks against L1 (#1639); and it recovers from an undetected L1 tip reorg (#1738).GET /bridge/v1/l1-info-tree-indexreturned HTTP 500 when the L1 bridge syncer trailed the L1 info tree syncer (an L1 bridge exit-tree index was used as an L1 info tree index) (#1794);ClaimProofHandlermetrics now report the real status code.l2gersyncnever recovered after an invalid GER was removed on-chain (#1732); its removal scan now respects RPCeth_getLogsblock-range caps (#1813).- AggSender stopped creating certificates beyond the last claim/bridge block on chains whose
finalizedtag lags (#1760);AggSender.MaxL2BlockNumberis honored again in the aggchain flow (#1673). - Query timeouts on large tables:
GET /bridge/v1/bridgesfiltered byfrom_address(#1780) and the claims endpoint (#1774). GET /bridge/v1/injected-l1-info-leafnow exposes the real L2 injection block/timestamp (#1819).force_ger_updatesent a real forced update only once, and could occasionally double-send (#1769, #1778).- Debug-trace bridge call matching only considers real
CALLframes (#1605);ParseMaxRangeFromErrorrecognisesquery exceeds max block range <N>(#1600); Docker builds embed version info again (#1623). exit_certificatestate dumps were silently truncated behind a load balancer (#1729).- aggsender: the
toBlock inconsistency for settled certlog isWarnonly whenagglayer-derived > db-stored; aggoracle: removed a falseIncorrect ChainIDwarning (#1900).
π·οΈ Image tags
| Variant | Shell | Tags |
|---|---|---|
| production | β | 0.11.0, 0.11, 0.11.0-no_shell, 0.11-no_shell |
| development | β | 0.11.0-dev, 0.11-dev |
Images are published to
ghcr.io/agglayer/aggkit. Thelatesttag currently resolves to the-dev(shell-enabled) image; pin an explicit version in production.
β Testing & Validation
- New e2e coverage: bridge tracker (
TestBridgeTrackerL1ToL2, redaction, auto-registration), bridge-service health andsync-statusfor all syncers, independent finality knobs, a newop-pp-2chainsenvironment withTestBridgeL2ToL2, the re-enabled remove-GER suite, and a Kurtosis-based suite forexit_certificate. force_ger_update: unit, simulated-backend and real-network e2e (TestForceGERUpdateE2E) tests, in both watch and poll modes.- The Glamsterdam-related changes have not yet been checked against a Glamsterdam-enabled node.
π¦ What's Changed
- feat: improve local e2e script to reuse existing temp dirs by @joanestebanr in #1591
- fix: cherry-pick #1589 - add query exceeds max block range to ParseMaxRangeFromError (develop) by @joanestebanr in #1600
- fix: debug trace bridge call matching by @arnaubennassar in #1605
- feat: cherry-pick: configurable batch block header retrieval via RPCClientConfig by @joanestebanr in #1606
- chore(deps): bump github.com/ethereum/go-ethereum from 1.17.2 to 1.17.3 by @dependabot[bot] in #1617
- chore(deps): bump github.com/mattn/go-sqlite3 from 1.14.42 to 1.14.44 by @dependabot[bot] in #1615
- chore(deps): bump go.uber.org/zap from 1.27.1 to 1.28.0 by @dependabot[bot] in #1614
- chore(deps): bump github.com/pelletier/go-toml/v2 from 2.3.0 to 2.3.1 by @dependabot[bot] in #1613
- chore(deps): bump google.golang.org/grpc from 1.80.0 to 1.81.1 by @dependabot[bot] in #1612
- chore(deps): bump github.com/invopop/jsonschema from 0.13.0 to 0.14.0 by @dependabot[bot] in #1603
- docs: document log availability requirement and reth receipt pruning config by @joanestebanr in #1610
- fix: cherry-pick: include .git in Docker build context for version embedding by @joanestebanr in #1623
- feat: Improve Backward/Forward LET tooling by @arnaubennassar in #1616
- fix: cherry-pick: validate legacy checkpoint block against L1 in CheckValidBlock (#1638) (#1639) by @joanestebanr in #1645
- docs: document log availability requirement and reth receipt pruning by @joanestebanr in #1664
- fix(ci): fix -dev images for release candidates and add -no_shell aliases by @joanestebanr in #1674
- fix: honor MaxL2BlockNumber in aggchain flow by @arnaubennassar in #1673
- chore: remove automatic Claude PR review, keep mention-only trigger by @arnaubennassar in #1695
- feat: autoclaim plan by @arnaubennassar in #1662
- fix(aggsender): rebuild FEP cert from scratch on reorged l1inforoot by @arnaubennassar in #1709
- chore: remove SonarQube/SonarCloud integration by @joanestebanr in #1719
- feat: new tool - exit_certificate by @krlosMata in #1582
- feat: add bridgeservicefinder package by @arnaubennassar in #1692
- fix(exit-certificate): re-seek debug_accountRange to avoid truncated state dump by @krlosMata in #1729
- feat(tools): force_ger_update β force periodic L1 GER updates by @arnaubennassar in #1730
- group dependabot updates by @arnaubennassar in #1733
- chore(deps): bump the all-dependencies group with 16 updates by @dependabot[bot] in #1734
- 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 @arnaubennassar in #1738
- 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
- feat(agglayer): make per-method cache policy configurable on the client by @joanestebanr in #1771
- feat(bridgetracker): add idle timeout eviction to bound registry memory by @joanestebanr in #1770
- chore(deps): bump github.com/pion/dtls/v3 from 3.1.2 to 3.1.4 by @dependabot[bot] in #1754
- fix(l1infotreesync): self-heal committed-state divergence by escalating reorg to last verified checkpoint by @arnaubennassar in #1773
- fix(claimsync): prevent GetClaimsPaged timeout on large claim tables by @arnaubennassar in #1774
- fix(force_ger_update): reset timer from our own confirmed send, not only the monitor by @arnaubennassar in #1778
- fix(bridgesync): index UPPER(from_address) and destination_network on bridge table by @arnaubennassar in #1780
- fix: bridgetracker API.md drift, fail-fast on unset L1GlobalExitRootAddress, unlimited default rate limit (#1781, #1782, #1783) by @arnaubennassar in #1784
- fix(bridgeservice): correct l1-info-tree-index fallback and cross-syncer error codes by @arnaubennassar in #1794
- feat: aggkit-proxy: add CORS support for REST and WebSocket endpoints by @joanestebanr in #1807
- feat(e2e): add two-chain anvil environment by @arnaubennassar in #1802
- feat: bridgeservicefinder: add IgnoreNetworkIDs to skip dead networks 1809 by @joanestebanr in #1810
- fix(l2gersync): adapt
isGERRemovedFromL2scan to RPC eth_getLogs block-range cap by @joanestebanr in #1813 - fix(bridgeservice): expose real L2 injection block/timestamp on injected-l1-info-leaf by @joanestebanr in #1819
- fix: aggkit-proxy: bali integration: bridge tracker activity endpoint, GER settlement/injection fixes by @joanestebanr in #1815
- feat(bridgeservice): add public config endpoint (GET /bridge/v1/config) by @joanestebanr in #1828
- fix: aggkit-proxy: wait for L1 info tree leaf availability before claiming L2->L1 bridges 1823 by @joanestebanr in #1829
- feat(bridgetracker): activity endpoint reports claim status like the tracker (pending/readyToClaim/claimed/error) by @joanestebanr in #1831
- fix: v0.11.0-rc9 proxy integration: bridgetracker step-error status handling, error-history cap, and bridgeservicefinder ignored-network fix by @joanestebanr in #1834
- fix(bridgeservice): encode BridgeResponse.GlobalIndex as BigIntString, not bare JSON number by @arnaubennassar in #1835
- feat(bridgetracker): add RPC-based fallback for recent bridges in /activity endpoint by @joanestebanr in #1838
- fix(bridgetracker): skip unverifiable intermediate steps once a bridge is already claimed by @joanestebanr in #1839
- fix: make L1 finality knobs independent β Finality() passthrough (#1846) and claim trimming (#1847) by @arnaubennassar in #1849
- feat(bridgetracker): parallelize activity/tracker scans and make bridge-service timeout configurable. Fix skip step by @joanestebanr in #1844
- fix: per-destination autoclaim cursors, bridge-service health sync status, bridgetracker emitter verification (#1651, #1689, #1751) by @arnaubennassar in #1854
- fix(ci): bump claude-code-action pin to fix Claude Interactive crashing on startup by @arnaubennassar in #1857
- fix(ci): pin Claude Interactive to claude-opus-5 by @arnaubennassar in #1858
- debug(ci): temporarily enable show_full_output on Claude Interactive by @arnaubennassar in #1859
- revert(ci): disable show_full_output on Claude Interactive by @arnaubennassar in #1860
- feat(bridgetracker): add SQLite-backed cache for tracker/activity state (#1822) by @joanestebanr in #1852
- feat(bridgetracker): step start_date/end_date from on-chain facts, not now by @joanestebanr in #1864
- fix(bridgetracker): redact error URLs + gate bridgeservicefinder auto-registration by @arnaubennassar in #1862
- chore(templates): add API Updates section to PR/release templates by @joanestebanr in #1867
- fix(bridgetracker): resolve exact settlement tx for WaitL1SettledGER by @joanestebanr in #1866
- fix(autoclaim): don't let a permanently disabled source pin the l2-to-lx block cursor by @arnaubennassar in #1882
- ci: use Sonnet 5.5 for @claude mentions on PRs by @arnaubennassar in #1880
- fix(autoclaim): EthTxManager defaults and start-block defaulting by @arnaubennassar in #1875
- feat(bridgeservice): sync status for all syncers with is_halted (#1861) by @arnaubennassar in #1877
- feat: proxy: expose cache size and alive counts as Prometheus metrics 1870 by @joanestebanr in #1871
- fix: paginate bridge tracker activity endpoint 442 by @joanestebanr in #1888
- feat(autoclaim): identify API requests by global index by @arnaubennassar in #1891
- chore: bump go-ethereum to v1.17.7 (Glamsterdam block hash) by @joanestebanr in #1893
- feat: proxy: use HashFromJSON and configurable RPC clients for L1 and L2 1896 by @joanestebanr in #1897
- feat: configurable gRPC client MaxDecodingMessageSize and downgrade toBlock inconsistency log by @joanestebanr in #1900
- refactor: remove autoclaim by @arnaubennassar in #1901
New Contributors
- @krlosMata made their first contribution in #1582
Full Changelog: v0.10.1...v0.11.0