Skip to content

v0.11.0

Choose a tag to compare

@joanestebanr joanestebanr released this 13 Oct 15:38
· 5 commits to develop since this release
v0.11.0
f7c15f5

The notes below are written relative to v0.10.1

πŸš€ What's New

  • aggkit-proxy service. 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) and GET /bridge/v1/root-by-ler (#1758); /health now reports per-source sync status and /sync-status covers all six syncers with is_halted (#1854, #1877).

  • New tool: exit_certificate (+ exit_certificate_claimer) (#1582): generates, signs and submits an agglayer Certificate for 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 configurable X, bounding certificate stalls for OP-FEP / DA provability.

  • eth_getLogs completeness verification + l1infotreesync self-healing (#1773, #1738): a block whose logs bloom is positive for a queried address but whose eth_getLogs response has no matching entry is now flagged and re-queried by block hash. l1infotreesync persists 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; fixes decoded message length too large when requesting aggchain proofs.

  • Independent L1 finality knobs (#1849): L1InfoTreeSync.Finality() no longer returns the multidownloader's BlockFinality, so valid mixed-finality configs are no longer rejected by the aggsender startup guard.

  • Configurable batch block header retrieval (#1606): new BatchBlockHeaderRetrieval (default true) for nodes without batch RPC support.

  • Improved Backward/Forward LET tooling (#1616) and a new bridgeservicefinder package (#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.md now 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.
  • MaxRequestsPerIPAndSecond default changes from 10 to 0 (unlimited) in [PublicREST], [AdminREST] and the proxy [REST] β€” the limit was never enforced there. [RPC] keeps 10 and is enforced (#1784).
  • CacheConfig (agglayer client) gains six per-method fields (cached/passthrough/forbidden). Cached = true alone no longer implies GetCertificateHeader caching: configs that rely on it must opt each method in explicitly (#1771).
  • The AggOracle EthTxManager defaults used wrong TOML keys and never applied. They are now WaitReceiptMaxTime / WaitReceiptCheckInterval (were GetReceiptMaxTime / 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-proof and the L1 path of GET /bridge/v1/injected-l1-info-leaf now return 404 (not indexed yet β€” retry later) or 503 (syncer halted / inconsistent) instead of 500. The Go client returns ErrNotFound on 404 (#1794, #1705).
  • GET /bridge/v1/sync-status always answers 200; component failures are reported in each entry's error field instead of a 500 (#1877).
  • global_index in GET /bridge/v1/bridges is 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 to InitialBlock (a full automatic resync) instead of halting forever. multidownloader StepSafe now 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 = 0

New 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 GetReceiptWaitInterval

Agglayer 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 = true

Standalone 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 in sync_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_id must 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-status no longer return 500; they always return 200 and report per-syncer failures in the new error field. / response now also includes sync_status and details.
    • /sync-status response: new optional l2_ger_info, l1_info_tree_info, claim_l1_info, claim_l2_info; NetworkSyncInfo gains is_halted and error.
    • /claim-proof, /l1-info-tree-index, /injected-l1-info-leaf: now document 404 (not indexed by the syncers yet, retry later) and 503 (syncer unavailable or resolving a reorg).
    • /injected-l1-info-leaf response: new optional injected_l2_block_num and injected_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 in v0.10.1), so there is no breaking change relative to the previous release. Endpoints (all GET):

    • /tracker/v1/health
    • /tracker/v1/bridge-address and /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.md and docs/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 InError retry path now validates the certificate's L1 info tree data and rebuilds from scratch when stale (#1709).
  • l1infotreesync stuck after upgrading from the legacy syncer (e.g. 0.8.x) to the multidownloader: CheckValidBlock now validates finalized checkpoint blocks against L1 (#1639); and it recovers from an undetected L1 tip reorg (#1738).
  • GET /bridge/v1/l1-info-tree-index returned 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); ClaimProofHandler metrics now report the real status code.
  • l2gersync never recovered after an invalid GER was removed on-chain (#1732); its removal scan now respects RPC eth_getLogs block-range caps (#1813).
  • AggSender stopped creating certificates beyond the last claim/bridge block on chains whose finalized tag lags (#1760); AggSender.MaxL2BlockNumber is honored again in the aggchain flow (#1673).
  • Query timeouts on large tables: GET /bridge/v1/bridges filtered by from_address (#1780) and the claims endpoint (#1774).
  • GET /bridge/v1/injected-l1-info-leaf now exposes the real L2 injection block/timestamp (#1819).
  • force_ger_update sent a real forced update only once, and could occasionally double-send (#1769, #1778).
  • Debug-trace bridge call matching only considers real CALL frames (#1605); ParseMaxRangeFromError recognises query exceeds max block range <N> (#1600); Docker builds embed version info again (#1623).
  • exit_certificate state dumps were silently truncated behind a load balancer (#1729).
  • aggsender: the toBlock inconsistency for settled cert log is Warn only when agglayer-derived > db-stored; aggoracle: removed a false Incorrect ChainID warning (#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. The latest tag 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 and sync-status for all syncers, independent finality knobs, a new op-pp-2chains environment with TestBridgeL2ToL2, the re-enabled remove-GER suite, and a Kurtosis-based suite for exit_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 isGERRemovedFromL2 scan 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

Full Changelog: v0.10.1...v0.11.0