Skip to content

Commit 902f300

Browse files
authored
fix: resolve JWT authentication race condition on validator restart (#2937)
1 parent 6ea742f commit 902f300

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

execution/client/client.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package client
2222

2323
import (
2424
"context"
25+
"fmt"
2526
"math/big"
2627
"sync"
2728
"time"
@@ -68,6 +69,7 @@ func New(
6869
cfg.RPCDialURL.String(),
6970
jwtSecret,
7071
cfg.RPCJWTRefreshInterval,
72+
logger,
7173
)
7274

7375
// Enforcing minimum rpc timeout
@@ -108,7 +110,12 @@ func (s *EngineClient) Name() string {
108110

109111
// Start the engine client.
110112
func (s *EngineClient) Start(ctx context.Context) error {
111-
// Start the Client.
113+
// Initialize the JWT token before making any RPC calls
114+
if err := s.Client.Initialize(); err != nil {
115+
return fmt.Errorf("failed to initialize RPC client: %w", err)
116+
}
117+
118+
// Start the Client background refresh loop.
112119
go s.Client.Start(ctx)
113120

114121
s.logger.Info(

execution/client/ethclient/engine_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ type stubRPCClient struct {
154154
t *testing.T
155155
}
156156

157+
func (tc *stubRPCClient) Initialize() error { return nil }
157158
func (tc *stubRPCClient) Start(context.Context) {}
158159
func (tc *stubRPCClient) Call(_ context.Context, target any, _ string, _ ...any) error {
159160
tc.t.Helper()

execution/client/ethclient/rpc/client.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"sync"
3030
"time"
3131

32+
"github.com/berachain/beacon-kit/log"
3233
"github.com/berachain/beacon-kit/primitives/encoding/json"
3334
beaconhttp "github.com/berachain/beacon-kit/primitives/net/http"
3435
"github.com/berachain/beacon-kit/primitives/net/jwt"
@@ -37,6 +38,7 @@ import (
3738
var _ Client = (*client)(nil)
3839

3940
type Client interface {
41+
Initialize() error
4042
Start(context.Context)
4143
Call(ctx context.Context, target any, method string, params ...any) error
4244
Close() error
@@ -56,6 +58,8 @@ type client struct {
5658
// jwtRefreshInterval is the interval at which the JWT token should be
5759
// refreshed.
5860
jwtRefreshInterval time.Duration
61+
// logger is the logger for the RPC client.
62+
logger log.Logger
5963

6064
// mu protects header for concurrent access.
6165
mu sync.RWMutex
@@ -69,6 +73,7 @@ func NewClient(
6973
url string,
7074
secret *jwt.Secret,
7175
jwtRefreshInterval time.Duration,
76+
logger log.Logger,
7277
) Client {
7378
rpc := &client{
7479
url: url,
@@ -84,6 +89,7 @@ func NewClient(
8489
jwtSecret: secret,
8590
jwtRefreshInterval: jwtRefreshInterval,
8691
header: http.Header{"Content-Type": {"application/json"}},
92+
logger: logger,
8793
}
8894

8995
return rpc
@@ -94,22 +100,30 @@ func (rpc *client) Start(ctx context.Context) {
94100
ticker := time.NewTicker(rpc.jwtRefreshInterval)
95101
defer ticker.Stop()
96102

97-
if err := rpc.updateHeader(); err != nil {
98-
panic(err)
99-
}
103+
// Initial JWT update is done in Initialize() now
100104
for {
101105
select {
102106
case <-ctx.Done():
103107
return
104108
case <-ticker.C:
105109
if err := rpc.updateHeader(); err != nil {
106-
// TODO: log or something.
110+
rpc.logger.Error("Failed to refresh JWT token", "error", err)
107111
continue
108112
}
109113
}
110114
}
111115
}
112116

117+
// Initialize sets up the initial JWT token. This should be called before
118+
// making any RPC calls to ensure a fresh token is available.
119+
func (rpc *client) Initialize() error {
120+
rpc.logger.Info("Initializing RPC client with fresh JWT token")
121+
if err := rpc.updateHeader(); err != nil {
122+
return fmt.Errorf("failed to initialize JWT token: %w", err)
123+
}
124+
return nil
125+
}
126+
113127
// Close closes the RPC client.
114128
func (rpc *client) Close() error {
115129
rpc.client.CloseIdleConnections()

0 commit comments

Comments
 (0)