How the Execution Client Communicates with the Op-Node in Base

The execution client and op-node communicate through the authenticated Engine JSON-RPC API, sharing a JWT secret to establish a protected channel on port 8551.

In the Base network architecture, the execution client (such as Geth, Reth, or Nethermind) and the consensus-layer op-node coordinate block execution and state synchronization through a standardized protocol. This analysis examines the base/node repository implementation, detailing exactly how the execution client communicates with the op-node using the Engine API with JWT authentication.

Engine API Architecture

The communication protocol relies on the Engine JSON-RPC API, a set of methods defined in the Optimism specification that allows the op-node to drive block execution. The execution client exposes this API on an authenticated HTTP endpoint, typically port 8551, supporting methods such as engine_newPayloadV1 and engine_forkchoiceUpdatedV1.

According to the source code in base/node, the execution client does not initiate connections to the op-node. Instead, the op-node acts as the client, sending requests to the execution client's Engine endpoint to submit L2 blocks and query execution state. The execution client responds with status codes and state data, creating a unidirectional control flow driven by the op-node.

JWT Authentication Setup

Security between the two components relies on shared JWT (JSON Web Token) authentication. Both services must use the identical JWT secret to validate requests, preventing unauthorized access to the Engine API.

Execution Client Configuration

The execution client entrypoint script generates and configures the JWT secret before starting the client binary. In geth/geth-entrypoint, the script writes the raw JWT secret to a file specified by the environment variable OP_NODE_L2_ENGINE_AUTH, then passes this file to Geth via the --authrpc.jwtsecret flag.

echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"

exec ./geth \
    --authrpc.jwtsecret="$OP_NODE_L2_ENGINE_AUTH" \
    --authrpc.port=8551 \
    --http.api=web3,debug,eth,net,engine \
    ...

This configuration ensures Geth listens on port 8551 and requires valid JWT tokens for all Engine API requests.

Op-Node Configuration

Before launching the op-node binary, the op-node-entrypoint script performs two critical steps. First, it waits for the execution client's Engine endpoint to become reachable. Second, it writes the same raw JWT secret to the shared file path used by the execution client.

until [ "$(curl -s --max-time 10 --connect-timeout 5 \
        -w '%{http_code}' -o /dev/null "${OP_NODE_L2_ENGINE_RPC/ws/http}")" -eq 401 ]; do
  echo "waiting for execution client to be ready"
  sleep 5
done

echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"
exec ./op-node

The op-node binary reads this JWT file and includes the secret in the authorization headers of its Engine API calls.

Readiness Detection and Handshake

The orchestration scripts implement a specific health-check mechanism to ensure proper startup sequencing. The op-node entrypoint repeatedly probes the execution client's Engine RPC URL (converted from WebSocket to HTTP protocol) until it receives an HTTP 401 response.

A 401 status indicates the execution client is online and accepting connections, but rejecting unauthenticated requests. This confirms the Engine API is ready to receive authenticated calls from the op-node, preventing race conditions during container startup.

Docker Compose Orchestration

The docker-compose.yml file in base/node defines two distinct services that implement this architecture:

  • execution: Runs the execution client entrypoint, exposing port 8551 for the Engine API
  • node: Runs the op-node entrypoint, configured to connect to the execution service's Engine endpoint

The services share the JWT secret through environment variables (OP_NODE_L2_ENGINE_AUTH and OP_NODE_L2_ENGINE_AUTH_RAW) and volume mounts, ensuring both containers access the same authentication credentials without hardcoding secrets into the images.

Summary

  • The execution client and op-node communicate via the Engine JSON-RPC API on port 8551, using methods like engine_newPayloadV1.
  • JWT authentication protects the Engine endpoint, with both services sharing the same secret written to OP_NODE_L2_ENGINE_AUTH.
  • The execution client (configured in geth/geth-entrypoint) exposes the authenticated API using the --authrpc.jwtsecret flag.
  • The op-node (configured in op-node-entrypoint) waits for HTTP 401 responses to confirm readiness, then authenticates requests using the shared JWT.
  • Docker Compose orchestrates the two services, ensuring proper secret sharing and network connectivity.

Frequently Asked Questions

What API specification does Base use for execution client communication?

Base implements the Engine API defined in the Optimism specification, which extends the Ethereum execution-layer consensus protocol. This API includes methods such as engine_newPayloadV1 and engine_forkchoiceUpdatedV1, allowing the op-node to instruct the execution client to process L2 blocks and update the fork choice state.

Why does the op-node entrypoint wait for an HTTP 401 response?

The entrypoint script waits for HTTP 401 (Unauthorized) because this status confirms the execution client's Engine API is actively listening and requiring authentication. A connection refusal or timeout would indicate the client hasn't finished initializing, while a 401 proves the service is ready to accept properly authenticated requests from the op-node.

Can the op-node communicate with execution clients other than Geth?

Yes, the architecture supports any execution client that implements the Optimism Engine API, including Reth, Nethermind, or Erigon. The base/node repository provides the Geth implementation as the default, but the JWT authentication pattern and Engine API interface remain consistent across compatible clients, provided they expose the standard RPC methods on the authenticated endpoint.

Where is the JWT secret stored in the Base node setup?

The JWT secret is stored in a file path specified by the OP_NODE_L2_ENGINE_AUTH environment variable, typically located at /jwtsecret or a similar path inside the container. Both the execution client and op-node entrypoint scripts write the raw secret from OP_NODE_L2_ENGINE_AUTH_RAW to this file before starting their respective binaries, ensuring both services use identical authentication tokens.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →