mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Tests for builder service (#11214)
* Tests for builder service * fix glob * minor changes to mock * add comments to mock * Revert "Auxiliary commit to revert individual files from bc62a140347e3cbd8bd82e99cf5e9deb98b74df0" This reverts commit c4c1016cb597b9340d1c81ab3816e037a6b97f9e. * correct comment * Do not init builder for empty endpoint * revert merging issues * better nil checks * test fix Co-authored-by: terencechain <terence@prysmaticlabs.com> Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -13,6 +13,8 @@ go_library(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
|
"//network:go_default_library",
|
||||||
|
"//network/authorization:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/network"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/network/authorization"
|
||||||
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -83,6 +85,15 @@ func (*requestLogger) observe(r *http.Request) (e error) {
|
|||||||
|
|
||||||
var _ observer = &requestLogger{}
|
var _ observer = &requestLogger{}
|
||||||
|
|
||||||
|
// BuilderClient provides a collection of helper methods for calling Builder API endpoints.
|
||||||
|
type BuilderClient interface {
|
||||||
|
NodeURL() string
|
||||||
|
GetHeader(ctx context.Context, slot types.Slot, parentHash [32]byte, pubkey [48]byte) (*ethpb.SignedBuilderBid, error)
|
||||||
|
RegisterValidator(ctx context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error
|
||||||
|
SubmitBlindedBlock(ctx context.Context, sb *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error)
|
||||||
|
Status(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
// Client provides a collection of helper methods for calling Builder API endpoints.
|
// Client provides a collection of helper methods for calling Builder API endpoints.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
hc *http.Client
|
hc *http.Client
|
||||||
@@ -94,7 +105,8 @@ type Client struct {
|
|||||||
// `host` is the base host + port used to construct request urls. This value can be
|
// `host` is the base host + port used to construct request urls. This value can be
|
||||||
// a URL string, or NewClient will assume an http endpoint if just `host:port` is used.
|
// a URL string, or NewClient will assume an http endpoint if just `host:port` is used.
|
||||||
func NewClient(host string, opts ...ClientOpt) (*Client, error) {
|
func NewClient(host string, opts ...ClientOpt) (*Client, error) {
|
||||||
u, err := urlForHost(host)
|
endpoint := covertEndPoint(host)
|
||||||
|
u, err := urlForHost(endpoint.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -304,3 +316,12 @@ func non200Err(response *http.Response) error {
|
|||||||
return errors.Wrap(ErrNotOK, fmt.Sprintf("unsupported error code: %d", response.StatusCode))
|
return errors.Wrap(ErrNotOK, fmt.Sprintf("unsupported error code: %d", response.StatusCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func covertEndPoint(ep string) network.Endpoint {
|
||||||
|
return network.Endpoint{
|
||||||
|
Url: ep,
|
||||||
|
Auth: network.AuthorizationData{ // Auth is not used for builder.
|
||||||
|
Method: authorization.None,
|
||||||
|
Value: "",
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|||||||
14
api/client/builder/testing/BUILD.bazel
Normal file
14
api/client/builder/testing/BUILD.bazel
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
load("@prysm//tools/go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["mock.go"],
|
||||||
|
importpath = "github.com/prysmaticlabs/prysm/v3/api/client/builder/testing",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//consensus-types/primitives:go_default_library",
|
||||||
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//proto/engine/v1:go_default_library",
|
||||||
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
49
api/client/builder/testing/mock.go
Normal file
49
api/client/builder/testing/mock.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockClient is a mock implementation of BuilderClient.
|
||||||
|
type MockClient struct {
|
||||||
|
RegisteredVals map[[48]byte]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a new, correctly initialized mock.
|
||||||
|
func NewClient() MockClient {
|
||||||
|
return MockClient{RegisteredVals: map[[48]byte]bool{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeURL --
|
||||||
|
func (MockClient) NodeURL() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeader --
|
||||||
|
func (MockClient) GetHeader(_ context.Context, _ types.Slot, _ [32]byte, _ [48]byte) (*ethpb.SignedBuilderBid, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterValidator --
|
||||||
|
func (m MockClient) RegisterValidator(_ context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error {
|
||||||
|
for _, r := range svr {
|
||||||
|
b := bytesutil.ToBytes48(r.Message.Pubkey)
|
||||||
|
m.RegisteredVals[b] = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitBlindedBlock --
|
||||||
|
func (MockClient) SubmitBlindedBlock(_ context.Context, _ *ethpb.SignedBlindedBeaconBlockBellatrix) (*v1.ExecutionPayload, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status --
|
||||||
|
func (MockClient) Status(_ context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
load("@prysm//tools/go:def.bzl", "go_library")
|
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
@@ -16,8 +16,6 @@ go_library(
|
|||||||
"//cmd/beacon-chain/flags:go_default_library",
|
"//cmd/beacon-chain/flags:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//network:go_default_library",
|
|
||||||
"//network/authorization:go_default_library",
|
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
@@ -28,3 +26,18 @@ go_library(
|
|||||||
"@io_opencensus_go//trace:go_default_library",
|
"@io_opencensus_go//trace:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["service_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//api/client/builder/testing:go_default_library",
|
||||||
|
"//beacon-chain/blockchain/testing:go_default_library",
|
||||||
|
"//beacon-chain/db/testing:go_default_library",
|
||||||
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
"//testing/assert:go_default_library",
|
||||||
|
"//testing/require:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/api/client/builder"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain"
|
||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||||
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
||||||
"github.com/prysmaticlabs/prysm/v3/network"
|
|
||||||
"github.com/prysmaticlabs/prysm/v3/network/authorization"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,22 +13,30 @@ type Option func(s *Service) error
|
|||||||
// FlagOptions for builder service flag configurations.
|
// FlagOptions for builder service flag configurations.
|
||||||
func FlagOptions(c *cli.Context) ([]Option, error) {
|
func FlagOptions(c *cli.Context) ([]Option, error) {
|
||||||
endpoint := c.String(flags.MevRelayEndpoint.Name)
|
endpoint := c.String(flags.MevRelayEndpoint.Name)
|
||||||
|
var client *builder.Client
|
||||||
|
if endpoint != "" {
|
||||||
|
var err error
|
||||||
|
client, err = builder.NewClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
opts := []Option{
|
opts := []Option{
|
||||||
WithBuilderEndpoints(endpoint),
|
WithBuilderClient(client),
|
||||||
}
|
}
|
||||||
return opts, nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithBuilderEndpoints sets the endpoint for the beacon chain builder service.
|
// WithBuilderClient sets the builder client for the beacon chain builder service.
|
||||||
func WithBuilderEndpoints(endpoint string) Option {
|
func WithBuilderClient(client builder.BuilderClient) Option {
|
||||||
return func(s *Service) error {
|
return func(s *Service) error {
|
||||||
s.cfg.builderEndpoint = covertEndPoint(endpoint)
|
s.cfg.builderClient = client
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHeadFetcher gets the head info from chain service.
|
// WithHeadFetcher gets the head info from chain service.
|
||||||
func WithHeadFetcher(svc *blockchain.Service) Option {
|
func WithHeadFetcher(svc blockchain.HeadFetcher) Option {
|
||||||
return func(s *Service) error {
|
return func(s *Service) error {
|
||||||
s.cfg.headFetcher = svc
|
s.cfg.headFetcher = svc
|
||||||
return nil
|
return nil
|
||||||
@@ -43,12 +50,3 @@ func WithDatabase(beaconDB db.HeadAccessDatabase) Option {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func covertEndPoint(ep string) network.Endpoint {
|
|
||||||
return network.Endpoint{
|
|
||||||
Url: ep,
|
|
||||||
Auth: network.AuthorizationData{ // Auth is not used for builder.
|
|
||||||
Method: authorization.None,
|
|
||||||
Value: "",
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package builder
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -10,7 +11,6 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v3/network"
|
|
||||||
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
v1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -30,15 +30,15 @@ type BlockBuilder interface {
|
|||||||
|
|
||||||
// config defines a config struct for dependencies into the service.
|
// config defines a config struct for dependencies into the service.
|
||||||
type config struct {
|
type config struct {
|
||||||
builderEndpoint network.Endpoint
|
builderClient builder.BuilderClient
|
||||||
beaconDB db.HeadAccessDatabase
|
beaconDB db.HeadAccessDatabase
|
||||||
headFetcher blockchain.HeadFetcher
|
headFetcher blockchain.HeadFetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service defines a service that provides a client for interacting with the beacon chain and MEV relay network.
|
// Service defines a service that provides a client for interacting with the beacon chain and MEV relay network.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
cfg *config
|
cfg *config
|
||||||
c *builder.Client
|
c builder.BuilderClient
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
@@ -56,18 +56,14 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.cfg.builderEndpoint.Url != "" {
|
if s.cfg.builderClient != nil && !reflect.ValueOf(s.cfg.builderClient).IsNil() {
|
||||||
c, err := builder.NewClient(s.cfg.builderEndpoint.Url)
|
s.c = s.cfg.builderClient
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.c = c
|
|
||||||
|
|
||||||
// Is the builder up?
|
// Is the builder up?
|
||||||
if err := s.c.Status(ctx); err != nil {
|
if err := s.c.Status(ctx); err != nil {
|
||||||
log.WithError(err).Error("Failed to check builder status")
|
log.WithError(err).Error("Failed to check builder status")
|
||||||
} else {
|
} else {
|
||||||
log.WithField("endpoint", c.NodeURL()).Info("Builder has been configured")
|
log.WithField("endpoint", s.c.NodeURL()).Info("Builder has been configured")
|
||||||
log.Warn("Outsourcing block construction to external builders adds non-trivial delay to block propagation time. " +
|
log.Warn("Outsourcing block construction to external builders adds non-trivial delay to block propagation time. " +
|
||||||
"Builder-constructed blocks or fallback blocks may get orphaned. Use at your own risk!")
|
"Builder-constructed blocks or fallback blocks may get orphaned. Use at your own risk!")
|
||||||
}
|
}
|
||||||
@@ -157,7 +153,7 @@ func (s *Service) RegisterValidator(ctx context.Context, reg []*ethpb.SignedVali
|
|||||||
return s.cfg.beaconDB.SaveRegistrationsByValidatorIDs(ctx, idxs, msgs)
|
return s.cfg.beaconDB.SaveRegistrationsByValidatorIDs(ctx, idxs, msgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configured returns true if the user has input a builder URL.
|
// Configured returns true if the user has configured a builder client.
|
||||||
func (s *Service) Configured() bool {
|
func (s *Service) Configured() bool {
|
||||||
return s.cfg.builderEndpoint.Url != ""
|
return s.c != nil && !reflect.ValueOf(s.c).IsNil()
|
||||||
}
|
}
|
||||||
|
|||||||
39
beacon-chain/builder/service_test.go
Normal file
39
beacon-chain/builder/service_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
buildertesting "github.com/prysmaticlabs/prysm/v3/api/client/builder/testing"
|
||||||
|
blockchainTesting "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||||
|
dbtesting "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||||
|
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||||
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_NewServiceWithBuilder(t *testing.T) {
|
||||||
|
s, err := NewService(context.Background(), WithBuilderClient(&buildertesting.MockClient{}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, true, s.Configured())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_NewServiceWithoutBuilder(t *testing.T) {
|
||||||
|
s, err := NewService(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, false, s.Configured())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_RegisterValidator(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
db := dbtesting.SetupDB(t)
|
||||||
|
headFetcher := &blockchainTesting.ChainService{}
|
||||||
|
builder := buildertesting.NewClient()
|
||||||
|
s, err := NewService(ctx, WithDatabase(db), WithHeadFetcher(headFetcher), WithBuilderClient(&builder))
|
||||||
|
require.NoError(t, err)
|
||||||
|
pubkey := bytesutil.ToBytes48([]byte("pubkey"))
|
||||||
|
var feeRecipient [20]byte
|
||||||
|
require.NoError(t, s.RegisterValidator(ctx, []*eth.SignedValidatorRegistrationV1{{Message: ð.ValidatorRegistrationV1{Pubkey: pubkey[:], FeeRecipient: feeRecipient[:]}}}))
|
||||||
|
assert.Equal(t, true, builder.RegisteredVals[pubkey])
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user