Skip to content

Commit d27aebf

Browse files
authored
app/eth2wrap: add support for extra headers (#3449)
Add `--beacon-node-headers` flag to `run` and `exit` command for passing HTTP header values to go-eth2-client client to allow for beacon node authentication. category: feature ticket: #3388
1 parent d3bf94e commit d27aebf

17 files changed

+232
-29
lines changed

app/app.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ type Config struct {
9595
ProcDirectory string
9696
ConsensusProtocol string
9797
Nickname string
98+
BeaconNodeHeaders []string
9899

99100
TestConfig TestConfig
100101
}
@@ -909,12 +910,17 @@ func newETH2Client(ctx context.Context, conf Config, life *lifecycle.Manager, cl
909910
log.Info(ctx, "Synthetic block proposals enabled")
910911
}
911912

912-
eth2Cl, err := configureEth2Client(ctx, forkVersion, conf.BeaconNodeAddrs, bnTimeout, conf.SyntheticBlockProposals)
913+
beaconNodeHeaders, err := eth2util.ParseBeaconNodeHeaders(conf.BeaconNodeHeaders)
914+
if err != nil {
915+
return nil, nil, err
916+
}
917+
918+
eth2Cl, err := configureEth2Client(ctx, forkVersion, conf.BeaconNodeAddrs, beaconNodeHeaders, bnTimeout, conf.SyntheticBlockProposals)
913919
if err != nil {
914920
return nil, nil, errors.Wrap(err, "new eth2 http client")
915921
}
916922

917-
submissionEth2Cl, err := configureEth2Client(ctx, forkVersion, conf.BeaconNodeAddrs, submissionBnTimeout, conf.SyntheticBlockProposals)
923+
submissionEth2Cl, err := configureEth2Client(ctx, forkVersion, conf.BeaconNodeAddrs, beaconNodeHeaders, submissionBnTimeout, conf.SyntheticBlockProposals)
918924
if err != nil {
919925
return nil, nil, errors.Wrap(err, "new submission eth2 http client")
920926
}
@@ -923,8 +929,8 @@ func newETH2Client(ctx context.Context, conf Config, life *lifecycle.Manager, cl
923929
}
924930

925931
// configureEth2Client configures a beacon node client with the provided settings.
926-
func configureEth2Client(ctx context.Context, forkVersion []byte, addrs []string, timeout time.Duration, syntheticBlockProposals bool) (eth2wrap.Client, error) {
927-
eth2Cl, err := eth2wrap.NewMultiHTTP(timeout, [4]byte(forkVersion), addrs...)
932+
func configureEth2Client(ctx context.Context, forkVersion []byte, addrs []string, headers map[string]string, timeout time.Duration, syntheticBlockProposals bool) (eth2wrap.Client, error) {
933+
eth2Cl, err := eth2wrap.NewMultiHTTP(timeout, [4]byte(forkVersion), headers, addrs...)
928934
if err != nil {
929935
return nil, errors.Wrap(err, "new eth2 http client")
930936
}

app/eth2wrap/eth2wrap.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,28 +85,29 @@ func WithSyntheticDuties(cl Client) Client {
8585
}
8686

8787
// NewMultiHTTP returns a new instrumented multi eth2 http client.
88-
func NewMultiHTTP(timeout time.Duration, forkVersion [4]byte, addresses ...string) (Client, error) {
89-
return Instrument(newClients(timeout, forkVersion, addresses)...)
88+
func NewMultiHTTP(timeout time.Duration, forkVersion [4]byte, headers map[string]string, addresses ...string) (Client, error) {
89+
return Instrument(newClients(timeout, forkVersion, headers, addresses)...)
9090
}
9191

9292
// newClients returns a slice of Client initialized with the provided settings.
93-
func newClients(timeout time.Duration, forkVersion [4]byte, addresses []string) []Client {
93+
func newClients(timeout time.Duration, forkVersion [4]byte, headers map[string]string, addresses []string) []Client {
9494
var clients []Client
9595
for _, address := range addresses {
96-
clients = append(clients, newBeaconClient(timeout, forkVersion, address))
96+
clients = append(clients, newBeaconClient(timeout, forkVersion, headers, address))
9797
}
9898

9999
return clients
100100
}
101101

102102
// newBeaconClient returns a Client with the provided settings.
103-
func newBeaconClient(timeout time.Duration, forkVersion [4]byte, address string) Client {
103+
func newBeaconClient(timeout time.Duration, forkVersion [4]byte, headers map[string]string, address string) Client {
104104
parameters := []eth2http.Parameter{
105105
eth2http.WithLogLevel(zeroLogInfo),
106106
eth2http.WithAddress(address),
107107
eth2http.WithTimeout(timeout),
108108
eth2http.WithAllowDelayedStart(true),
109109
eth2http.WithEnforceJSON(featureset.Enabled(featureset.JSONRequests)),
110+
eth2http.WithExtraHeaders(headers),
110111
}
111112

112113
cl := newLazy(func(ctx context.Context) (Client, error) {

app/eth2wrap/eth2wrap_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func TestErrors(t *testing.T) {
171171
ctx := context.Background()
172172

173173
t.Run("network dial error", func(t *testing.T) {
174-
cl, err := eth2wrap.NewMultiHTTP(time.Hour, [4]byte{}, "localhost:22222")
174+
cl, err := eth2wrap.NewMultiHTTP(time.Hour, [4]byte{}, map[string]string{}, "localhost:22222")
175175
require.NoError(t, err)
176176

177177
_, err = cl.SlotsPerEpoch(ctx)
@@ -186,7 +186,7 @@ func TestErrors(t *testing.T) {
186186
}))
187187

188188
t.Run("http timeout", func(t *testing.T) {
189-
cl, err := eth2wrap.NewMultiHTTP(time.Millisecond, [4]byte{}, srv.URL)
189+
cl, err := eth2wrap.NewMultiHTTP(time.Millisecond, [4]byte{}, map[string]string{}, srv.URL)
190190
require.NoError(t, err)
191191

192192
_, err = cl.SlotsPerEpoch(ctx)
@@ -199,7 +199,7 @@ func TestErrors(t *testing.T) {
199199
ctx, cancel := context.WithCancel(ctx)
200200
cancel()
201201

202-
cl, err := eth2wrap.NewMultiHTTP(time.Millisecond, [4]byte{}, srv.URL)
202+
cl, err := eth2wrap.NewMultiHTTP(time.Millisecond, [4]byte{}, map[string]string{}, srv.URL)
203203
require.NoError(t, err)
204204

205205
_, err = cl.SlotsPerEpoch(ctx)
@@ -251,7 +251,7 @@ func TestCtxCancel(t *testing.T) {
251251

252252
bmock, err := beaconmock.New()
253253
require.NoError(t, err)
254-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, bmock.Address())
254+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, map[string]string{}, bmock.Address())
255255
require.NoError(t, err)
256256

257257
cancel() // Cancel context before calling method.
@@ -310,7 +310,7 @@ func TestOneError(t *testing.T) {
310310
bmock.Address(), // Valid
311311
}
312312

313-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, addresses...)
313+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, map[string]string{}, addresses...)
314314
require.NoError(t, err)
315315

316316
eth2Resp, err := eth2Cl.Spec(ctx, &eth2api.SpecOpts{})
@@ -341,7 +341,7 @@ func TestOneTimeout(t *testing.T) {
341341
bmock.Address(), // Valid
342342
}
343343

344-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Minute, [4]byte{}, addresses...)
344+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Minute, [4]byte{}, map[string]string{}, addresses...)
345345
require.NoError(t, err)
346346

347347
eth2Resp, err := eth2Cl.Spec(ctx, &eth2api.SpecOpts{})
@@ -364,7 +364,7 @@ func TestOnlyTimeout(t *testing.T) {
364364
defer srv.Close()
365365
defer cancel() // Cancel the context before stopping the server.
366366

367-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Minute, [4]byte{}, srv.URL)
367+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Minute, [4]byte{}, map[string]string{}, srv.URL)
368368
require.NoError(t, err)
369369

370370
// Start goroutine that is blocking trying to create the client.
@@ -426,7 +426,7 @@ func TestLazy(t *testing.T) {
426426
httputil.NewSingleHostReverseProxy(target).ServeHTTP(w, r)
427427
}))
428428

429-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, srv1.URL, srv2.URL)
429+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte{}, map[string]string{}, srv1.URL, srv2.URL)
430430
require.NoError(t, err)
431431

432432
// Both proxies are disabled, so this should fail.
@@ -505,7 +505,7 @@ func TestLazyDomain(t *testing.T) {
505505

506506
forkVersionHex, err := hex.DecodeString(test.in)
507507
require.NoError(t, err)
508-
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte(forkVersionHex), srv.URL)
508+
eth2Cl, err := eth2wrap.NewMultiHTTP(time.Second, [4]byte(forkVersionHex), map[string]string{}, srv.URL)
509509
require.NoError(t, err)
510510

511511
voluntaryExitDomain := eth2p0.DomainType{0x04, 0x00, 0x00, 0x00}

app/eth2wrap/fallback.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type FallbackClient struct {
2222
// NewFallbackClient initializes a FallbackClient with the provided settings
2323
func NewFallbackClient(timeout time.Duration, forkVersion [4]byte, addresses []string) *FallbackClient {
2424
return &FallbackClient{
25-
clients: newClients(timeout, forkVersion, addresses),
25+
clients: newClients(timeout, forkVersion, map[string]string{}, addresses),
2626
}
2727
}
2828

app/peerinfo/peerinfo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (p *PeerInfo) sendOnce(ctx context.Context, now time.Time) {
202202

203203
name := p2p.PeerName(peerID)
204204

205-
p.nicknames[name] = resp.Nickname
205+
p.nicknames[name] = resp.GetNickname()
206206
log.Info(ctx, "Peer name to nickname mappings", z.Any("nicknames", p.nicknames))
207207

208208
// Validator git hash with regex.

cmd/exit.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type exitConfig struct {
3838
Log log.Config
3939
All bool
4040
testnetConfig eth2util.Network
41+
BeaconNodeHeaders []string
4142
}
4243

4344
func newExitCmd(cmds ...*cobra.Command) *cobra.Command {
@@ -74,6 +75,7 @@ const (
7475
testnetChainID
7576
testnetGenesisTimestamp
7677
testnetCapellaHardFork
78+
beaconNodeHeaders
7779
)
7880

7981
func (ef exitFlag) String() string {
@@ -116,6 +118,8 @@ func (ef exitFlag) String() string {
116118
return "testnet-genesis-timestamp"
117119
case testnetCapellaHardFork:
118120
return "testnet-capella-hard-fork"
121+
case beaconNodeHeaders:
122+
return "beacon-node-headers"
119123
default:
120124
return "unknown"
121125
}
@@ -177,6 +181,8 @@ func bindExitFlags(cmd *cobra.Command, config *exitConfig, flags []exitCLIFlag)
177181
cmd.Flags().Int64Var(&config.testnetConfig.GenesisTimestamp, "testnet-genesis-timestamp", 0, "Genesis timestamp of the custom test network.")
178182
case testnetCapellaHardFork:
179183
cmd.Flags().StringVar(&config.testnetConfig.CapellaHardFork, "testnet-capella-hard-fork", "", "Capella hard fork version of the custom test network.")
184+
case beaconNodeHeaders:
185+
cmd.Flags().StringSliceVar(&config.BeaconNodeHeaders, "beacon-node-headers", nil, "Comma separated list of headers formatted as header=value")
180186
}
181187

182188
if f.required {
@@ -185,8 +191,8 @@ func bindExitFlags(cmd *cobra.Command, config *exitConfig, flags []exitCLIFlag)
185191
}
186192
}
187193

188-
func eth2Client(ctx context.Context, u []string, timeout time.Duration, forkVersion [4]byte) (eth2wrap.Client, error) {
189-
cl, err := eth2wrap.NewMultiHTTP(timeout, forkVersion, u...)
194+
func eth2Client(ctx context.Context, headers map[string]string, u []string, timeout time.Duration, forkVersion [4]byte) (eth2wrap.Client, error) {
195+
cl, err := eth2wrap.NewMultiHTTP(timeout, forkVersion, headers, u...)
190196
if err != nil {
191197
return nil, err
192198
}

cmd/exit_broadcast.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func newBcastFullExitCmd(runFunc func(context.Context, exitConfig) error) *cobra
6969
{testnetChainID, false},
7070
{testnetGenesisTimestamp, false},
7171
{testnetCapellaHardFork, false},
72+
{beaconNodeHeaders, false},
7273
})
7374

7475
bindLogFlags(cmd.Flags(), &config.Log)
@@ -98,6 +99,11 @@ func newBcastFullExitCmd(runFunc func(context.Context, exitConfig) error) *cobra
9899
return errors.New(fmt.Sprintf("if you want to specify exit file directory for all validators, you must provide %s and not %s.", exitFromDir.String(), exitFromFile.String()))
99100
}
100101

102+
err := eth2util.ValidateBeaconNodeHeaders(config.BeaconNodeHeaders)
103+
if err != nil {
104+
return err
105+
}
106+
101107
return nil
102108
})
103109

@@ -121,7 +127,12 @@ func runBcastFullExit(ctx context.Context, config exitConfig) error {
121127
return errors.Wrap(err, "load cluster lock", z.Str("lock_file_path", config.LockFilePath))
122128
}
123129

124-
eth2Cl, err := eth2Client(ctx, config.BeaconNodeEndpoints, config.BeaconNodeTimeout, [4]byte(cl.GetForkVersion()))
130+
beaconNodeHeaders, err := eth2util.ParseBeaconNodeHeaders(config.BeaconNodeHeaders)
131+
if err != nil {
132+
return err
133+
}
134+
135+
eth2Cl, err := eth2Client(ctx, beaconNodeHeaders, config.BeaconNodeEndpoints, config.BeaconNodeTimeout, [4]byte(cl.GetForkVersion()))
125136
if err != nil {
126137
return errors.Wrap(err, "create eth2 client for specified beacon node(s)", z.Any("beacon_nodes_endpoints", config.BeaconNodeEndpoints))
127138
}

cmd/exit_broadcast_internal_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func testRunBcastFullExitCmdFlow(t *testing.T, fromFile bool, all bool) {
107107
require.NoError(t, beaconMock.Close())
108108
}()
109109

110-
eth2Cl, err := eth2Client(ctx, []string{beaconMock.Address()}, 10*time.Second, [4]byte(lock.ForkVersion))
110+
eth2Cl, err := eth2Client(ctx, map[string]string{}, []string{beaconMock.Address()}, 10*time.Second, [4]byte(lock.ForkVersion))
111111
require.NoError(t, err)
112112

113113
handler, addLockFiles := obolapimock.MockServer(false, eth2Cl)

cmd/exit_fetch_internal_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func testRunFetchExitFullFlow(t *testing.T, all bool) {
9090
require.NoError(t, beaconMock.Close())
9191
}()
9292

93-
eth2Cl, err := eth2Client(ctx, []string{beaconMock.Address()}, 10*time.Second, [4]byte(lock.ForkVersion))
93+
eth2Cl, err := eth2Client(ctx, map[string]string{}, []string{beaconMock.Address()}, 10*time.Second, [4]byte(lock.ForkVersion))
9494
require.NoError(t, err)
9595

9696
handler, addLockFiles := obolapimock.MockServer(false, eth2Cl)

cmd/exit_list.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,15 @@ func newListActiveValidatorsCmd(runFunc func(context.Context, exitConfig) error)
4949
{testnetChainID, false},
5050
{testnetGenesisTimestamp, false},
5151
{testnetCapellaHardFork, false},
52+
{beaconNodeHeaders, false},
5253
})
5354

5455
bindLogFlags(cmd.Flags(), &config.Log)
5556

57+
wrapPreRunE(cmd, func(*cobra.Command, []string) error {
58+
return eth2util.ValidateBeaconNodeHeaders(config.BeaconNodeHeaders)
59+
})
60+
5661
return cmd
5762
}
5863

@@ -87,7 +92,12 @@ func listActiveVals(ctx context.Context, config exitConfig) ([]string, error) {
8792
return nil, errors.Wrap(err, "load cluster lock", z.Str("lock_file_path", config.LockFilePath))
8893
}
8994

90-
eth2Cl, err := eth2Client(ctx, config.BeaconNodeEndpoints, config.BeaconNodeTimeout, [4]byte{}) // fine to avoid initializing a fork version, we're just querying the BN
95+
beaconNodeHeaders, err := eth2util.ParseBeaconNodeHeaders(config.BeaconNodeHeaders)
96+
if err != nil {
97+
return nil, err
98+
}
99+
100+
eth2Cl, err := eth2Client(ctx, beaconNodeHeaders, config.BeaconNodeEndpoints, config.BeaconNodeTimeout, [4]byte{}) // fine to avoid initializing a fork version, we're just querying the BN
91101
if err != nil {
92102
return nil, errors.Wrap(err, "create eth2 client for specified beacon node(s)", z.Any("beacon_nodes_endpoints", config.BeaconNodeEndpoints))
93103
}

0 commit comments

Comments
 (0)