From 84e0fd0348f055d506459ec4cdb399cd9b081395 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Mar 2026 17:12:42 +0200 Subject: [PATCH 1/3] fix(pkg/da): fallback to polling when ws cannot connect --- apps/evm/cmd/run.go | 2 +- apps/grpc/cmd/run.go | 2 +- apps/testapp/cmd/run.go | 2 +- pkg/cmd/run_node.go | 2 +- pkg/da/jsonrpc/client.go | 13 ++++++++++--- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/evm/cmd/run.go b/apps/evm/cmd/run.go index ce7755ccb6..a88e548d21 100644 --- a/apps/evm/cmd/run.go +++ b/apps/evm/cmd/run.go @@ -59,7 +59,7 @@ var RunCmd = &cobra.Command{ return err } - blobClient, err := blobrpc.NewWSClient(cmd.Context(), nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") + blobClient, err := blobrpc.NewWSClient(cmd.Context(), logger, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") if err != nil { return fmt.Errorf("failed to create blob client: %w", err) } diff --git a/apps/grpc/cmd/run.go b/apps/grpc/cmd/run.go index 3d1d77a6d9..22ca71f587 100644 --- a/apps/grpc/cmd/run.go +++ b/apps/grpc/cmd/run.go @@ -108,7 +108,7 @@ func createSequencer( genesis genesis.Genesis, executor execution.Executor, ) (coresequencer.Sequencer, error) { - blobClient, err := blobrpc.NewWSClient(ctx, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") + blobClient, err := blobrpc.NewWSClient(ctx, logger, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") if err != nil { return nil, fmt.Errorf("failed to create blob client: %w", err) } diff --git a/apps/testapp/cmd/run.go b/apps/testapp/cmd/run.go index 1022d1bce3..8584882175 100644 --- a/apps/testapp/cmd/run.go +++ b/apps/testapp/cmd/run.go @@ -111,7 +111,7 @@ func createSequencer( genesis genesis.Genesis, executor execution.Executor, ) (coresequencer.Sequencer, error) { - blobClient, err := blobrpc.NewWSClient(ctx, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") + blobClient, err := blobrpc.NewWSClient(ctx, logger, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") if err != nil { return nil, fmt.Errorf("failed to create blob client: %w", err) } diff --git a/pkg/cmd/run_node.go b/pkg/cmd/run_node.go index b0a36c889a..113a9229ba 100644 --- a/pkg/cmd/run_node.go +++ b/pkg/cmd/run_node.go @@ -149,7 +149,7 @@ func StartNode( } } - blobClient, err := blobrpc.NewWSClient(ctx, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") + blobClient, err := blobrpc.NewWSClient(ctx, logger, nodeConfig.DA.Address, nodeConfig.DA.AuthToken, "") if err != nil { return fmt.Errorf("failed to create blob client: %w", err) } diff --git a/pkg/da/jsonrpc/client.go b/pkg/da/jsonrpc/client.go index c856cdd7b9..b95703d12d 100644 --- a/pkg/da/jsonrpc/client.go +++ b/pkg/da/jsonrpc/client.go @@ -8,6 +8,7 @@ import ( libshare "github.com/celestiaorg/go-square/v3/share" "github.com/filecoin-project/go-jsonrpc" + "github.com/rs/zerolog" ) // Client dials the celestia-node RPC "blob" and "header" namespaces. @@ -72,9 +73,15 @@ func NewClient(ctx context.Context, addr, token string, authHeaderName string) ( // Automatically converts http:// to ws:// (and https:// to wss://). // Supports channel-based subscriptions (e.g. Subscribe). // Note: WebSocket connections are eager — they connect at creation time -// and will fail immediately if the server is unavailable. -func NewWSClient(ctx context.Context, addr, token string, authHeaderName string) (*Client, error) { - return NewClient(ctx, httpToWS(addr), token, authHeaderName) +// if it fails, we fallback to non websocket connection for the whole runtime process. +func NewWSClient(ctx context.Context, logger zerolog.Logger, addr, token string, authHeaderName string) (*Client, error) { + client, err := NewClient(ctx, httpToWS(addr), token, authHeaderName) + if err != nil { + logger.Warn().Msg("connection to websocket failed, failling back to DA polling") + return NewClient(ctx, addr, token, authHeaderName) + } + + return client, nil } // BlobAPI mirrors celestia-node's blob module (nodebuilder/blob/blob.go). From 53ec7cbb4d85385c47f6072643cc0e79b57e08ad Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Mar 2026 17:16:30 +0200 Subject: [PATCH 2/3] log err and fix typos --- pkg/da/jsonrpc/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/da/jsonrpc/client.go b/pkg/da/jsonrpc/client.go index b95703d12d..afdd645692 100644 --- a/pkg/da/jsonrpc/client.go +++ b/pkg/da/jsonrpc/client.go @@ -77,7 +77,7 @@ func NewClient(ctx context.Context, addr, token string, authHeaderName string) ( func NewWSClient(ctx context.Context, logger zerolog.Logger, addr, token string, authHeaderName string) (*Client, error) { client, err := NewClient(ctx, httpToWS(addr), token, authHeaderName) if err != nil { - logger.Warn().Msg("connection to websocket failed, failling back to DA polling") + logger.Warn().Err(err).Msg("DA websocket connection failed, falling back to DA polling") return NewClient(ctx, addr, token, authHeaderName) } From 102f2975d1d92979b6cb142340f8a6f058371c43 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Mar 2026 17:20:51 +0200 Subject: [PATCH 3/3] rewording --- pkg/da/jsonrpc/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/da/jsonrpc/client.go b/pkg/da/jsonrpc/client.go index afdd645692..664da4114b 100644 --- a/pkg/da/jsonrpc/client.go +++ b/pkg/da/jsonrpc/client.go @@ -73,7 +73,7 @@ func NewClient(ctx context.Context, addr, token string, authHeaderName string) ( // Automatically converts http:// to ws:// (and https:// to wss://). // Supports channel-based subscriptions (e.g. Subscribe). // Note: WebSocket connections are eager — they connect at creation time -// if it fails, we fallback to non websocket connection for the whole runtime process. +// if the initial WS dial fails, falls back to HTTP polling for the entire session. func NewWSClient(ctx context.Context, logger zerolog.Logger, addr, token string, authHeaderName string) (*Client, error) { client, err := NewClient(ctx, httpToWS(addr), token, authHeaderName) if err != nil {