mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
cmd,eth,beacon: accept custom http headers for beacon api
This commit is contained in:
parent
2333dcdb24
commit
70e2451c57
6 changed files with 50 additions and 17 deletions
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
eth2client "github.com/attestantio/go-eth2-client"
|
eth2client "github.com/attestantio/go-eth2-client"
|
||||||
eth2api "github.com/attestantio/go-eth2-client/api"
|
eth2api "github.com/attestantio/go-eth2-client/api"
|
||||||
|
|
@ -41,26 +42,40 @@ var (
|
||||||
|
|
||||||
// Client is a wrapper around the attestantio/go-eth2-client beacon api client.
|
// Client is a wrapper around the attestantio/go-eth2-client beacon api client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
url string
|
url string
|
||||||
client eth2client.Service
|
http *http.Client
|
||||||
|
extraHeaders map[string]string
|
||||||
|
client eth2client.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a Client for the given server URL.
|
// NewClient creates a Client for the given server URL.
|
||||||
func NewClient(ctx context.Context, server string) (*Client, error) {
|
func NewClient(ctx context.Context, server string, headers []string) (*Client, error) {
|
||||||
|
// Parse additional headers.
|
||||||
|
extraHeaders := make(map[string]string)
|
||||||
|
for _, h := range headers {
|
||||||
|
s := strings.Split(h, ":")
|
||||||
|
if len(s) != 2 {
|
||||||
|
return nil, fmt.Errorf("malformed extra header: %s", h)
|
||||||
|
}
|
||||||
|
extraHeaders[s[0]] = s[1]
|
||||||
|
}
|
||||||
client, err := eth2http.New(
|
client, err := eth2http.New(
|
||||||
ctx,
|
ctx,
|
||||||
eth2http.WithAddress(server),
|
eth2http.WithAddress(server),
|
||||||
eth2http.WithLogLevel(zerolog.WarnLevel),
|
eth2http.WithLogLevel(zerolog.WarnLevel),
|
||||||
eth2http.WithEnforceJSON(true),
|
eth2http.WithEnforceJSON(true),
|
||||||
|
eth2http.WithExtraHeaders(extraHeaders),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Client{
|
return &Client{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
url: server,
|
url: server,
|
||||||
client: client,
|
http: &http.Client{},
|
||||||
|
extraHeaders: extraHeaders,
|
||||||
|
client: client,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +83,7 @@ func NewClient(ctx context.Context, server string) (*Client, error) {
|
||||||
// the beacon server.
|
// the beacon server.
|
||||||
func (c *Client) Bootstrap(root common.Hash) (*types.Bootstrap, error) {
|
func (c *Client) Bootstrap(root common.Hash) (*types.Bootstrap, error) {
|
||||||
var bs types.Bootstrap
|
var bs types.Bootstrap
|
||||||
if err := fetch(fmt.Sprintf("%s/%s/%s", c.url, beaconLightClientBootstrap, root.String()), &bs); err != nil {
|
if err := c.fetch(fmt.Sprintf("%s/%s/%s", c.url, beaconLightClientBootstrap, root.String()), &bs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &bs, nil
|
return &bs, nil
|
||||||
|
|
@ -78,7 +93,7 @@ func (c *Client) Bootstrap(root common.Hash) (*types.Bootstrap, error) {
|
||||||
// include the next sync committee and finalized header from the period.
|
// include the next sync committee and finalized header from the period.
|
||||||
func (c *Client) GetRangeUpdate(start, count int) ([]*types.LightClientUpdate, error) {
|
func (c *Client) GetRangeUpdate(start, count int) ([]*types.LightClientUpdate, error) {
|
||||||
var u []*types.LightClientUpdate
|
var u []*types.LightClientUpdate
|
||||||
if err := fetch(fmt.Sprintf("%s/%s?start_period=%d&count=%d", c.url, beaconLightClientUpdate, start, count), &u); err != nil {
|
if err := c.fetch(fmt.Sprintf("%s/%s?start_period=%d&count=%d", c.url, beaconLightClientUpdate, start, count), &u); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
|
|
@ -89,7 +104,7 @@ func (c *Client) GetRangeUpdate(start, count int) ([]*types.LightClientUpdate, e
|
||||||
// beacon api server.
|
// beacon api server.
|
||||||
func (c *Client) GetOptimisticUpdate() (*types.LightClientUpdate, error) {
|
func (c *Client) GetOptimisticUpdate() (*types.LightClientUpdate, error) {
|
||||||
var u types.LightClientUpdate
|
var u types.LightClientUpdate
|
||||||
if err := fetch(fmt.Sprintf("%s/%s", c.url, beaconLightClientOptimisticUpdate), &u); err != nil {
|
if err := c.fetch(fmt.Sprintf("%s/%s", c.url, beaconLightClientOptimisticUpdate), &u); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &u, nil
|
return &u, nil
|
||||||
|
|
@ -99,7 +114,7 @@ func (c *Client) GetOptimisticUpdate() (*types.LightClientUpdate, error) {
|
||||||
// beacon api server.
|
// beacon api server.
|
||||||
func (c *Client) GetFinalityUpdate() (*types.LightClientUpdate, error) {
|
func (c *Client) GetFinalityUpdate() (*types.LightClientUpdate, error) {
|
||||||
var u types.LightClientUpdate
|
var u types.LightClientUpdate
|
||||||
if err := fetch(fmt.Sprintf("%s/%s", c.url, beaconLightClientFinalityUpdate), &u); err != nil {
|
if err := c.fetch(fmt.Sprintf("%s/%s", c.url, beaconLightClientFinalityUpdate), &u); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &u, nil
|
return &u, nil
|
||||||
|
|
@ -118,11 +133,21 @@ func (c *Client) GetBlock(root common.Hash) (*eth2spec.VersionedSignedBeaconBloc
|
||||||
return resp.Data, nil
|
return resp.Data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetch(url string, val any) error {
|
func (c *Client) fetch(url string, val any) error {
|
||||||
resp, err := http.Get(url)
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range c.extraHeaders {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
resp, err := c.http.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed http request: %w", err)
|
return fmt.Errorf("failed http request: %w", err)
|
||||||
}
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return fmt.Errorf("failed http request: status %d", resp.StatusCode)
|
||||||
|
}
|
||||||
b, err := io.ReadAll(resp.Body)
|
b, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read response: %w", err)
|
return fmt.Errorf("failed to read response: %w", err)
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ type LightClient struct {
|
||||||
|
|
||||||
// Bootstrap retrieves a light client bootstrap and authenticates it against the
|
// Bootstrap retrieves a light client bootstrap and authenticates it against the
|
||||||
// provided trusted root.
|
// provided trusted root.
|
||||||
func Bootstrap(ctx context.Context, server string, root common.Hash) (*LightClient, error) {
|
func Bootstrap(server string, headers []string, root common.Hash) (*LightClient, error) {
|
||||||
api, err := beaclient.NewClient(ctx, server)
|
api, err := beaclient.NewClient(context.Background(), server, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to connect to beacon server: %w", err)
|
return nil, fmt.Errorf("failed to connect to beacon server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@ var (
|
||||||
utils.LogDebugFlag,
|
utils.LogDebugFlag,
|
||||||
utils.LogBacktraceAtFlag,
|
utils.LogBacktraceAtFlag,
|
||||||
utils.BeaconAPIFlag,
|
utils.BeaconAPIFlag,
|
||||||
|
utils.BeaconAPIHeadersFlag,
|
||||||
utils.BeaconTrustedBlockRootFlag,
|
utils.BeaconTrustedBlockRootFlag,
|
||||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -915,6 +915,11 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
Usage: "server which provides the beacon light client apis",
|
Usage: "server which provides the beacon light client apis",
|
||||||
Category: flags.BeaconCategory,
|
Category: flags.BeaconCategory,
|
||||||
}
|
}
|
||||||
|
BeaconAPIHeadersFlag = &cli.StringSliceFlag{
|
||||||
|
Name: "beacon.api.headers",
|
||||||
|
Usage: "headers to provide with each request",
|
||||||
|
Category: flags.BeaconCategory,
|
||||||
|
}
|
||||||
BeaconTrustedBlockRootFlag = &cli.StringFlag{
|
BeaconTrustedBlockRootFlag = &cli.StringFlag{
|
||||||
Name: "beacon.wss",
|
Name: "beacon.wss",
|
||||||
Usage: "root of trusted block within the weak-subjectivity window",
|
Usage: "root of trusted block within the weak-subjectivity window",
|
||||||
|
|
@ -1599,6 +1604,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
// Avoid conflicting network flags
|
// Avoid conflicting network flags
|
||||||
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag)
|
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag)
|
||||||
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||||
|
CheckExclusive(ctx, DeveloperFlag, BeaconAPIFlag) // Can't use both simulated beacon and blsync
|
||||||
|
|
||||||
// Set configurations from CLI flags
|
// Set configurations from CLI flags
|
||||||
setEtherbase(ctx, cfg)
|
setEtherbase(ctx, cfg)
|
||||||
|
|
@ -1859,6 +1865,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
Fatalf("Must set both beacon api flag and beacon trusted block root flag to use beacon light client")
|
Fatalf("Must set both beacon api flag and beacon trusted block root flag to use beacon light client")
|
||||||
}
|
}
|
||||||
cfg.BeaconAPI = ctx.String(BeaconAPIFlag.Name)
|
cfg.BeaconAPI = ctx.String(BeaconAPIFlag.Name)
|
||||||
|
cfg.BeaconAPIHeaders = ctx.StringSlice(BeaconAPIHeadersFlag.Name)
|
||||||
cfg.BeaconTrustedBlockRoot = ctx.String(BeaconTrustedBlockRootFlag.Name)
|
cfg.BeaconTrustedBlockRoot = ctx.String(BeaconTrustedBlockRootFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -277,7 +276,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.BeaconAPI != "" && config.BeaconTrustedBlockRoot != "" {
|
if config.BeaconAPI != "" && config.BeaconTrustedBlockRoot != "" {
|
||||||
beacon, err := light.Bootstrap(context.Background(), config.BeaconAPI, common.HexToHash(config.BeaconTrustedBlockRoot))
|
beacon, err := light.Bootstrap(config.BeaconAPI, config.BeaconAPIHeaders, common.HexToHash(config.BeaconTrustedBlockRoot))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ type Config struct {
|
||||||
|
|
||||||
// Beacon light client options
|
// Beacon light client options
|
||||||
BeaconAPI string
|
BeaconAPI string
|
||||||
|
BeaconAPIHeaders []string
|
||||||
BeaconTrustedBlockRoot string
|
BeaconTrustedBlockRoot string
|
||||||
|
|
||||||
// Database options
|
// Database options
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue