Skip to content

feat: bridgeservicefinder: add IgnoreNetworkIDs to skip dead networks 1809 - #1810

Merged
joanestebanr merged 8 commits into
developfrom
feat/1809-ignore-dead-networks
Sep 1, 2026
Merged

feat: bridgeservicefinder: add IgnoreNetworkIDs to skip dead networks 1809#1810
joanestebanr merged 8 commits into
developfrom
feat/1809-ignore-dead-networks

Conversation

@joanestebanr

@joanestebanr joanestebanr commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

🔄 Changes Summary

  • Add Config.IgnoreNetworkIDs []uint32 to bridgeservicefinder: networkIDs (rollupIDs) listed here are excluded entirely from on-chain resolution.
    • buildInitialCache skips them during enumeration (no RollupIDToRollupData call, no contract reads, no health probe).
    • The live listener skips them when a rollup-manager lifecycle event (CreateNewRollup/CreateNewAggchain/AddExistingRollup) announces them, so they are never added to the watched-address set either.
    • A static Config.BridgeURLs override for a networkID is still served even if that networkID is also listed in IgnoreNetworkIDs — the ignore only skips on-chain inspection, never a config override.
  • This addresses the first suggestion in feat: proxy: reduce the startup time due dead networks #1809: avoid known-dead networks (decommissioned/unreachable test rollups) slowing down proxy startup and event processing with on-chain reads and health-check timeouts that can never succeed. The second suggestion in the issue (parallelizing discovery) is out of scope for this PR.
  • Also added the new field (empty by default) to the proxy binary's default TOML config template.

⚠️ Breaking Changes

  • None. IgnoreNetworkIDs defaults to an empty list, so existing deployments are unaffected.

📋 Config Updates

  • 🧾 New optional field IgnoreNetworkIDs on BridgeServiceFinder, shared by the autoclaim and proxy binaries since both reuse the same bridgeservicefinder package. Defaults to [] (nothing ignored). Documented in docs/autoclaim.md's config table and added (empty) to the proxy default config template.

    AutoClaim (AutoClaim.BridgeServiceFinder section):

    [AutoClaim.BridgeServiceFinder]
    RollupManagerAddr = "0x0000000000000000000000000000000000000000"
    IgnoreNetworkIDs = [5, 12]

    Proxy ([BridgeServiceFinder] section):

    [BridgeServiceFinder]
    RollupManagerAddr = "0x0000000000000000000000000000000000000000"
    BlockFinality = "FinalizedBlock"
    PollInterval = "30s"
    BlockChunkSize = 10000
    HealthCheckPath = "/"
    HealthCheckTimeout = "5s"
    RequireAllHealthyOnStart = false
    IgnoreNetworkIDs = [5, 12]

    IgnoreNetworkIDs takes a list of the dead networks' networkIDs (rollupIDs) — e.g. [5, 12] above skips networks 5 and 12 — and can be pasted directly under the existing BridgeServiceFinder block in either config, replacing the default IgnoreNetworkIDs = [].

✅ Testing

  • 🤖 Automatic: new unit tests TestStart_IgnoreNetworkIDs_SkipsEnumeration and TestLiveDiscovery_IgnoredNetworkIsNeverRegistered in bridgeservicefinder; full bridgeservicefinder and proxy/config suites pass; golangci-lint clean; go build ./... passes.

🐞 Issues

🔗 Related PRs

  • None

📝 Notes

  • The ignore list only affects on-chain enumeration/live discovery; the pre-existing config-seeding step in buildInitialCache (which installs BridgeURLs/RPCURLs overrides) runs independently and is unaffected, so an ignored+config-overridden network is still served.
  • No dedicated proxy-specific doc lists BridgeServiceFinder fields individually (only docs/autoclaim.md has a per-field table, since AutoClaim reuses the same package), so no further doc update was needed there.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 209b94fb90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +244 to +246
if _, ignored := f.ignoreNetworkIDs[rollupID]; ignored {
f.logger.Infof("network %d is in IgnoreNetworkIDs, skipping on-chain resolution", rollupID)
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip startup probes for ignored static overrides

When a network appears in both IgnoreNetworkIDs and BridgeURLs, the earlier config-seeding loop still places it in the cache, and Start subsequently calls probeAll, which probes every cached entry. An unreachable ignored override therefore still incurs the configured health-check timeout and, with RequireAllHealthyOnStart=true, makes startup fail with ErrServicesUnhealthyOnStart, contrary to the new option's promise to avoid health probes for ignored networks while continuing to serve their static overrides. The startup probing step needs to exclude ignored IDs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 769721c: probeAll now skips any networkID in IgnoreNetworkIDs, so a config-overridden-but-ignored network's cache entry is served but never health-probed (never counted toward RequireAllHealthyOnStart either). Added TestStart_IgnoreNetworkIDs_SkipsHealthProbe to cover it.

joanestebanr added a commit that referenced this pull request Aug 21, 2026
…alth probe

probeAll iterated every cache entry unconditionally, including one installed
by the config-seeding step for a networkID that is both config-overridden
and listed in IgnoreNetworkIDs. That defeated the point of ignoring a
known-dead network: its /health probe still incurred the configured
timeout, and under RequireAllHealthyOnStart=true an unreachable ignored
override could still fail Start with ErrServicesUnhealthyOnStart.

probeAll now skips any networkID in Config.IgnoreNetworkIDs; its entry is
still served by GetURL, with healthy defaulting to false (never probed).

Found by review on #1810.
@joanestebanr joanestebanr self-assigned this Aug 21, 2026
taylanpince
taylanpince previously approved these changes Aug 21, 2026
joanestebanr added a commit that referenced this pull request Aug 25, 2026
L1's chain data is baked into its image at build time and never advances
past block 384. Anchoring L2 genesis to L1's head (previous commit) fixes
LoadEnv, but once the sequencer has produced ~600s (max_sequencer_drift)
worth of L2 blocks since genesis, op-node's origin-selector needs a newer
L1 origin than block 384 to keep going and never finds one, stalling the
chain forever mid-test-run.

Raise max_sequencer_drift to a week so the sequencer never needs to look
for a newer L1 origin within the lifetime of a test run.

Found while investigating CI failures on #1810.
joanestebanr and others added 8 commits September 1, 2026 09:15
Config.IgnoreNetworkIDs lists networkIDs (rollupIDs) that are excluded
entirely from on-chain resolution: buildInitialCache skips them during
enumeration (no RollupIDToRollupData call, no contract reads, no health
probe) and the live listener skips them when a rollup-manager lifecycle
event announces them (CreateNewRollup/CreateNewAggchain/AddExistingRollup).

This avoids known-dead networks (decommissioned or unreachable test
rollups) slowing down proxy startup and event processing with on-chain
reads and health-check timeouts that can never succeed. A static
Config.BridgeURLs override for a networkID is still served even if that
networkID is also listed in IgnoreNetworkIDs.

Fixes #1809
Documents the new bridgeservicefinder.Config.IgnoreNetworkIDs field in the
proxy binary's default TOML template. No other doc location lists
BridgeServiceFinder fields individually for the proxy binary (only
docs/autoclaim.md has a per-field table, already updated for AutoClaim).
…alth probe

probeAll iterated every cache entry unconditionally, including one installed
by the config-seeding step for a networkID that is both config-overridden
and listed in IgnoreNetworkIDs. That defeated the point of ignoring a
known-dead network: its /health probe still incurred the configured
timeout, and under RequireAllHealthyOnStart=true an unreachable ignored
override could still fail Start with ErrServicesUnhealthyOnStart.

probeAll now skips any networkID in Config.IgnoreNetworkIDs; its entry is
still served by GetURL, with healthy defaulting to false (never probed).

Found by review on #1810.
Add the missing BridgeServiceFinder fields (BlockFinality,
BlockChunkSize, HealthCheckPath, HealthCheckTimeout,
RequireAllHealthyOnStart, IgnoreNetworkIDs) and the empty
BridgeURLs/RPCURLs map sections to config/default.go, matching the
values already used in proxy/config/default.go and the Default*
constants defined in bridgeservicefinder/config.go.

Also add the missing BridgeURLs/RPCURLs sections to
proxy/config/default.go for the same reason.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…l-clock

op-pp's L1 image (arnaubennassar/geth:op-pp) has its chain data baked in at
build time and never advances past that snapshot. The op-geth entrypoint was
patching the L2 genesis timestamp to date +%s (real wall-clock) on every
start, so the gap between the L2 genesis and its L1 origin block grows by one
day for every day that passes since the L1 image was built. Once that drift
exceeded rollup.json's max_sequencer_drift (600s), op-node's sequencer could
never find a valid L1 origin for the first post-genesis block and the L2
chain stalled forever at block 0 -- surfacing as
"wait for MintableERC20 deployment: context deadline exceeded" during
LoadEnv, since op-pp's L1 snapshot is from Feb 2026 (~6 months of drift by
now).

Fix: read L1's actual head timestamp and use it to patch the L2 genesis
instead of wall-clock time, keeping L2 genesis anchored to L1's frozen origin
regardless of what day the test actually runs.

Verified locally: op-geth-001/op-node-001 went from stuck at block 0 to
actively sequencing new L2 blocks.

Note: since L1 never advances, the chain still stalls again once L2's
virtual time drifts past max_sequencer_drift from the anchored origin
(~1800s of L2 time in local testing) -- well past LoadEnv/MintableERC20
deployment, but a longer-running test could still hit it. Left as a known
follow-up rather than widening scope here.
L1's chain data is baked into its image at build time and never advances
past block 384. Anchoring L2 genesis to L1's head (previous commit) fixes
LoadEnv, but once the sequencer has produced ~600s (max_sequencer_drift)
worth of L2 blocks since genesis, op-node's origin-selector needs a newer
L1 origin than block 384 to keep going and never finds one, stalling the
chain forever mid-test-run.

Raise max_sequencer_drift to a week so the sequencer never needs to look
for a newer L1 origin within the lifetime of a test run.

Found while investigating CI failures on #1810.
@joanestebanr
joanestebanr force-pushed the feat/1809-ignore-dead-networks branch from 2923a82 to 4e855a1 Compare September 1, 2026 07:15
@joanestebanr
joanestebanr enabled auto-merge (squash) September 1, 2026 08:25
@joanestebanr
joanestebanr merged commit 0917bee into develop Sep 1, 2026
31 checks passed
@joanestebanr
joanestebanr deleted the feat/1809-ignore-dead-networks branch September 1, 2026 09:47
joanestebanr added a commit that referenced this pull request Sep 1, 2026
L1's chain data is baked into its image at build time and never advances
past block 384. Anchoring L2 genesis to L1's head (previous commit) fixes
LoadEnv, but once the sequencer has produced ~600s (max_sequencer_drift)
worth of L2 blocks since genesis, op-node's origin-selector needs a newer
L1 origin than block 384 to keep going and never finds one, stalling the
chain forever mid-test-run.

Raise max_sequencer_drift to a week so the sequencer never needs to look
for a newer L1 origin within the lifetime of a test run.

Found while investigating CI failures on #1810.
joanestebanr added a commit that referenced this pull request Sep 2, 2026
…, GER settlement/injection fixes (#1815)

## 🔄 Changes Summary
- **`feat(bridgetracker)`**: new `GET
/tracker/v1/activity/from/{from_address}` endpoint that scans every
bridge service known to the `bridgeservicefinder` (via new
`Finder.NetworkIDs()`) for bridges sent by an address and resolves each
one's claim state (`ActivityCache`, `ActivitySource`,
`ActivityQuerier`/`ActivityBridgeScanner`/`ActivityClaimChecker` ports).
Opt-in via `includeTracking=true` to also register still-unclaimed
bridges with the tracker. Endpoint is only registered when wired
(`proxy/cmd/run.go`), and swagger docs are regenerated.
- **`feat(bridgetracker)`**: `StepClaimed` is now its own tracked step
with a dedicated `ClaimedResolver` that fetches the claim tx/block from
the destination network's bridge service, decoupled from
`StepWaitingClaim`, which now checks `isClaimed()` on-chain directly
through a new `ClaimChecker` port instead of waiting on the indexed
claim record — faster and authoritative, at the cost of not carrying
claim tx details itself (that's what the new `Claimed` step result is
for). The on-chain binding/cache logic is factored out of
`ActivitySource` into `sources/claim_checker.go`
(`contractClaimCheckers`) and shared by both the tracker engine and the
activity endpoint.
- **`fix(bridgetracker)`**: introduce `domain.ScannedBridge` to track
which network's bridge service actually reported a scanned bridge
(`NetworkID`), distinct from `Bridge.OriginNetwork` (the bridged
*asset*'s origin network) — the two diverge when an asset is re-bridged
across more than one hop, which was feeding the wrong
`sourceBridgeNetwork` into `isClaimed()` and the wrong network into
`TrackingID`/the activity endpoint's `bridge_network_id` for such
bridges.
- **`feat(bridgetracker)`**: new `GET /bridge-address[/{network_id}]`
endpoint, resolving the bridge contract address for one network or every
network currently known — opt-in via `Config.BridgeAddressResolver`,
wired in `proxy/cmd/run.go` off `bridgeservicefinder.Finder` directly.
Backed by a new `Config.BridgeAddress` override map on
`bridgeservicefinder.Finder` itself (priority: per-network entry, then
`[0]` as the default, then the rollup manager's own on-chain
`BridgeAddress()`).
- **`feat(bridgetracker)`**: `ClaimResult` now also carries
`BlockTimestamp` alongside `BlockNumber`. `InjectedGERResult` is
restructured into `L1InfoTreeLeaf` (the L1
`UpdateL1InfoTree`/`UpdateL1InfoTreeV2` event that produced the covering
leaf) and an optional `L2InjectedGER` (the actual L2 block/timestamp the
GER was injected at on the destination network) — fixing #1818, where
the L1 block was returned in the L2 field's place. When the
destination's bridge-service instance doesn't report the L2 injection
block itself (`injected_l2_block_num`/`injected_l2_block_timestamp` on
`GET /bridge/v1/injected-l1-info-leaf`), `GERSource` falls back to
scanning that network's own `GlobalExitRootManagerL2` contract for the
`UpdateHashChainValue` event backwards in chunks, via the new
`Tracker.L2GlobalExitRootAddress` per-network contract address map (a
workaround-only fallback, see its doc) — bounded by a new
`Tracker.L2InjectionLookbackBlocks` (default 1,000 blocks) instead of
always walking back to genesis.
- **`fix(bridgetracker)`**: resolve the settled GER correctly when the
settlement tx has no `UpdateL1InfoTree` event: walk backwards on L1 for
the most recent earlier one instead of surfacing "not ready" forever,
excluding same-block logs from a later transaction, and querying
`eth_getLogs` in chunks that respect providers' 10,000-block range cap.
- **`fix(bridgetracker)`**: gate certificate settlement on the
settlement tx actually being visible on L1 (not just the agglayer client
reporting `Settled`), avoiding a premature `TransactionReceipt` lookup
that would otherwise fail.

## ⚠️ Breaking Changes
- None. `Config.BridgeAddressResolver` and the new `bridgetracker`
activity/bridge-address ports are additive/opt-in.

## 📋 Config Updates
- 🧾 New optional `BridgeServiceFinder.BridgeAddress` map (networkID →
address override), default empty — consulted by the new `GET
/bridge-address[/{network_id}]` endpoint before falling back to the
rollup manager's on-chain `BridgeAddress()`. That endpoint itself is
gated by `Config.BridgeAddressResolver` (Go-level wiring, not a TOML
key); unset leaves both routes unregistered.
- 🧾 New optional `Tracker.ActivityIdleTimeout` (defaults to
`IdleTimeout` if unset) — idle timeout for the activity endpoint's own
cache.
- 🧾 New optional `Tracker.L2GlobalExitRootAddress` (networkID →
`GlobalExitRootManagerL2` address map, default empty) and
`Tracker.L2InjectionLookbackBlocks` (default `1000`) — workaround-only
fallback for a destination network whose bridge-service instance
predates L2 injection block reporting (#1819); defaults leave behavior
unchanged for everyone else.

  ```toml
  [BridgeServiceFinder.BridgeAddress]
# optional per-network override, consulted in this priority order by
Finder.BridgeAddress:
# BridgeAddress[networkID], then BridgeAddress[0] (default for every
other network), then the
  # rollup manager's own on-chain BridgeAddress()
  0 = "0xShared_L1_bridge_address_used_as_the_default"
  5 = "0xNetwork5s_own_bridge_address"

  [Tracker]
  ActivityIdleTimeout = "30m"
  L2InjectionLookbackBlocks = 1000

# Workaround only: uncomment for a destination network whose
bridge-service instance does not
  # report the L2 block a covering GER was injected at.
  # [Tracker.L2GlobalExitRootAddress]
  # 1 = "0x..."
  ```

## ✅ Testing
- 🤖 **Automatic**: `go build ./...` and `go test ./bridgetracker/...
./bridgeservicefinder/... ./autoclaim/... ./proxy/...` pass, including
new/updated regression tests for the activity endpoint
(`activity_test.go`, `sources/activity_test.go`, `cache_test.go`), the
claimed-step split (`resolve_steps_test.go`, `engine_test.go`), the new
bridge-address endpoint (`bridge_address_test.go`), the settlement GER
backwards-search fix (`settlement_test.go`), and the L2 injection
fallback/lookback cap (`sources_test.go`'s
`TestGERSourceInjectedGER_FallsBackToL2Scan` and
`TestFindL2InjectionBlockBackwards`, `proxy/config/config_test.go`).

## 🐞 Issues
- Fixes #1818.

## 🔗 Related PRs
- None.

## 📝 Notes
- This branch's history still contains commits for
`bridgeservicefinder`'s `IgnoreNetworkIDs` and the `l2gersync`
`eth_getLogs` chunk-cap fix (originally developed alongside this work) —
both landed directly on `develop` in the meantime (#1810, #1813), so
neither shows up in this PR's diff anymore despite still being present
in the branch's git history.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: proxy: reduce the startup time due dead networks

3 participants