Commit 595d5916 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6705 from ethereum-optimism/jg/fix_op_node_dial

op-node: Make it resilient to not yet ready RPC URLs
parents d08d4ce9 5f587f0a
...@@ -3,6 +3,8 @@ package client ...@@ -3,6 +3,8 @@ package client
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"net/url"
"regexp" "regexp"
"time" "time"
...@@ -103,17 +105,31 @@ func NewRPC(ctx context.Context, lgr log.Logger, addr string, opts ...RPCOption) ...@@ -103,17 +105,31 @@ func NewRPC(ctx context.Context, lgr log.Logger, addr string, opts ...RPCOption)
func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string, attempts int, opts ...rpc.ClientOption) (*rpc.Client, error) { func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string, attempts int, opts ...rpc.ClientOption) (*rpc.Client, error) {
bOff := backoff.Exponential() bOff := backoff.Exponential()
return backoff.Do(ctx, attempts, bOff, func() (*rpc.Client, error) { return backoff.Do(ctx, attempts, bOff, func() (*rpc.Client, error) {
if !IsURLAvailable(addr) {
log.Warn("failed to dial address, but may connect later", "addr", addr)
return nil, fmt.Errorf("address unavailable (%s)", addr)
}
client, err := rpc.DialOptions(ctx, addr, opts...) client, err := rpc.DialOptions(ctx, addr, opts...)
if err != nil { if err != nil {
if client == nil { return nil, fmt.Errorf("failed to dial address (%s): %w", addr, err)
return nil, fmt.Errorf("failed to dial address (%s): %w", addr, err)
}
log.Warn("failed to dial address, but may connect later", "addr", addr, "err", err)
} }
return client, nil return client, nil
}) })
} }
func IsURLAvailable(address string) bool {
u, err := url.Parse(address)
if err != nil {
return false
}
conn, err := net.DialTimeout("tcp", u.Host, 5*time.Second)
if err != nil {
return false
}
conn.Close()
return true
}
// BaseRPCClient is a wrapper around a concrete *rpc.Client instance to make it compliant // BaseRPCClient is a wrapper around a concrete *rpc.Client instance to make it compliant
// with the client.RPC interface. // with the client.RPC interface.
// It sets a timeout of 10s on CallContext & 20s on BatchCallContext made through it. // It sets a timeout of 10s on CallContext & 20s on BatchCallContext made through it.
......
...@@ -76,32 +76,32 @@ func New(ctx context.Context, cfg *Config, log log.Logger, snapshotLog log.Logge ...@@ -76,32 +76,32 @@ func New(ctx context.Context, cfg *Config, log log.Logger, snapshotLog log.Logge
func (n *OpNode) init(ctx context.Context, cfg *Config, snapshotLog log.Logger) error { func (n *OpNode) init(ctx context.Context, cfg *Config, snapshotLog log.Logger) error {
if err := n.initTracer(ctx, cfg); err != nil { if err := n.initTracer(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the trace: %w", err)
} }
if err := n.initL1(ctx, cfg); err != nil { if err := n.initL1(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init L1: %w", err)
} }
if err := n.initRuntimeConfig(ctx, cfg); err != nil { if err := n.initRuntimeConfig(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the runtime config: %w", err)
} }
if err := n.initL2(ctx, cfg, snapshotLog); err != nil { if err := n.initL2(ctx, cfg, snapshotLog); err != nil {
return err return fmt.Errorf("failed to init L2: %w", err)
} }
if err := n.initRPCSync(ctx, cfg); err != nil { if err := n.initRPCSync(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init RPC sync: %w", err)
} }
if err := n.initP2PSigner(ctx, cfg); err != nil { if err := n.initP2PSigner(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the P2P signer: %w", err)
} }
if err := n.initP2P(ctx, cfg); err != nil { if err := n.initP2P(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the P2P stack: %w", err)
} }
// Only expose the server at the end, ensuring all RPC backend components are initialized. // Only expose the server at the end, ensuring all RPC backend components are initialized.
if err := n.initRPCServer(ctx, cfg); err != nil { if err := n.initRPCServer(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the RPC server: %w", err)
} }
if err := n.initMetricsServer(ctx, cfg); err != nil { if err := n.initMetricsServer(ctx, cfg); err != nil {
return err return fmt.Errorf("failed to init the metrics server: %w", err)
} }
return nil return nil
} }
...@@ -128,7 +128,7 @@ func (n *OpNode) initL1(ctx context.Context, cfg *Config) error { ...@@ -128,7 +128,7 @@ func (n *OpNode) initL1(ctx context.Context, cfg *Config) error {
} }
if err := cfg.Rollup.ValidateL1Config(ctx, n.l1Source); err != nil { if err := cfg.Rollup.ValidateL1Config(ctx, n.l1Source); err != nil {
return err return fmt.Errorf("failed to validate the L1 config: %w", err)
} }
// Keep subscribed to the L1 heads, which keeps the L1 maintainer pointing to the best headers to sync // Keep subscribed to the L1 heads, which keeps the L1 maintainer pointing to the best headers to sync
......
...@@ -3,8 +3,6 @@ package client ...@@ -3,8 +3,6 @@ package client
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"net/url"
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/client" "github.com/ethereum-optimism/optimism/op-node/client"
...@@ -53,7 +51,7 @@ func DialRollupClientWithTimeout(timeout time.Duration, log log.Logger, url stri ...@@ -53,7 +51,7 @@ func DialRollupClientWithTimeout(timeout time.Duration, log log.Logger, url stri
func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string) (*rpc.Client, error) { func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string) (*rpc.Client, error) {
bOff := backoff.Fixed(defaultRetryTime) bOff := backoff.Fixed(defaultRetryTime)
return backoff.Do(ctx, defaultRetryCount, bOff, func() (*rpc.Client, error) { return backoff.Do(ctx, defaultRetryCount, bOff, func() (*rpc.Client, error) {
if !IsURLAvailable(addr) { if !client.IsURLAvailable(addr) {
log.Warn("failed to dial address, but may connect later", "addr", addr) log.Warn("failed to dial address, but may connect later", "addr", addr)
return nil, fmt.Errorf("address unavailable (%s)", addr) return nil, fmt.Errorf("address unavailable (%s)", addr)
} }
...@@ -64,16 +62,3 @@ func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string) ...@@ -64,16 +62,3 @@ func dialRPCClientWithBackoff(ctx context.Context, log log.Logger, addr string)
return client, nil return client, nil
}) })
} }
func IsURLAvailable(address string) bool {
u, err := url.Parse(address)
if err != nil {
return false
}
conn, err := net.DialTimeout("tcp", u.Host, 5*time.Second)
if err != nil {
return false
}
conn.Close()
return true
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment