Skip to content

[build-only, do not merge] op-service: make the RPC pre-flight check proxy-aware - #2

Open
philippecamacho wants to merge 1 commit into
espresso/batcherfrom
espresso/proxy-aware-url-check
Open

[build-only, do not merge] op-service: make the RPC pre-flight check proxy-aware#2
philippecamacho wants to merge 1 commit into
espresso/batcherfrom
espresso/proxy-aware-url-check

Conversation

@philippecamacho

Copy link
Copy Markdown
Collaborator

Do not merge

This PR exists to build a test image. The fix belongs in celo-org/optimism on espresso/batcherop-service/client/rpc.go is byte-identical in both repos (blob 63694ced…), and this fork's branch is celo-org's head plus the enclave-packaging commit, so anything else landed here is erased by the next sync. Opening it as a PR (rather than pushing to the branch) publishes op-batcher-enclave-app:pr-N / op-batcher-tee:pr-N without touching espresso/batcher, and closes cleanly afterwards.

The bug

IsURLAvailable probes an endpoint with a raw net.Dial before rpc.DialOptions is attempted:

dialer := net.Dialer{Timeout: timeout}
conn, err := dialer.DialContext(ctx, "tcp", addr)   // ignores HTTP_PROXY

That dial ignores HTTP_PROXY/HTTPS_PROXY, so it tests a route the RPC client itself never takes — the client dials the proxy.

Inside an AWS Nitro enclave there is no direct route at all; every packet leaves through a local proxy on 127.0.0.1:10000. So the probe fails for every address, and CheckAndDial gives up before reaching rpc.DialOptions, which would have succeeded. The TEE batcher dies during setup, 30 attempts then exit 1:

crit Application failed
     failed to setup: failed to dial L1 RPC: operation failed permanently after 30 attempts:
     address unavailable (http://erpc.devnets.espresso.private:4000/main/evm/11155111)

Not specific to that endpoint — the same check would reject every URL the batcher uses. L1 is simply dialled first.

The fix

Probe whatever the client will actually dial: when a proxy is configured for the URL, check the proxy's address instead of the target's. With no proxy, behaviour is unchanged.

Port defaulting moves into a hostPort helper so it applies to the proxy URL too, preserving the existing fail-open for schemes with no well-known port.

The environment lookup is indirected through a package var because net/http reads proxy env once per process, which a test cannot undo. No new dependency — go.mod/go.sum are untouched.

Verification

go vet ./op-service/client/     clean
go test ./op-service/client/    ok (4.4s)
go build ./op-batcher/...       ok

New tests cover: reachable/unreachable target with no proxy; target unreachable but proxy reachable (the enclave case, which fails without this change); proxy unreachable; unknown scheme fails open; and hostPort defaulting. The two pre-existing tests, TestIsURLAvailableLocal and TestIsURLAvailableNonLocal, still pass.

That is unit-level only. The point of this PR is the image, so the real check is a TEE batcher on the Chaos testnet reaching erpc from inside the enclave. Results will be posted here before the celo-org PR is opened.

Framing for upstream

A pre-flight check that tests a path the client never uses is arguably an upstream bug rather than an Espresso quirk — CheckAndDial and the timeout removal both came from ethereum-optimism (ethereum-optimism#13146, ethereum-optimism#16864). Worth proposing there once it has run in production.

🤖 Generated with Claude Code

IsURLAvailable probes an endpoint with a raw net.Dial before
rpc.DialOptions is attempted. That dial ignores HTTP_PROXY/HTTPS_PROXY,
so it tests a route the RPC client itself never takes.

Inside an AWS Nitro enclave there is no direct route at all — every
packet leaves through a local proxy — so the probe fails for every
address and CheckAndDial gives up before reaching rpc.DialOptions, which
would have succeeded. The TEE batcher dies during setup:

  failed to setup: failed to dial L1 RPC: operation failed permanently
  after 30 attempts: address unavailable (http://erpc...:4000/...)

Probe whatever the client will actually dial: when a proxy is configured
for the URL, check the proxy's address instead of the target's. With no
proxy, behaviour is unchanged.

Port defaulting moves into a hostPort helper so it applies to the proxy
URL too, keeping the existing fail-open for schemes with no well-known
port. The environment lookup is indirected through a package var because
net/http reads proxy env once per process, which a test cannot undo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant