mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
Unregister validator - fix behind feature flag (#12316)
* adding changes to blocks * trying out expiration * adding implementation, have WIP for tests * adding unit tests for cache * fixing bazel complaints * fix linting * adding safe check for unint type * changing approach to safety check * adding cache to bazel to test fixing build * reverting bazel change and adding flag to usage * implementing interface on mock to fix build error * fixing unit tests * fixing unit test * fixing unit tests * fixing linting * fixing more unit tests * fixing produce blinded block tests * Update beacon-chain/cache/registration.go Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * resolving review comments * fixing cache * Update beacon-chain/cache/registration.go Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * Update beacon-chain/cache/registration.go Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * fixing time logic * adding context to trace * fix bazel lint * fixing context dependency * fix linting * Update cmd/beacon-chain/flags/base.go Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> * addressing review comments * fixing deepsource issues * improving the default settings * fixing bazel * removing irrelevant unit test * updating name --------- Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
This commit is contained in:
parent
d382abe198
commit
83416f31a5
@ -12,6 +12,7 @@ go_library(
|
||||
deps = [
|
||||
"//api/client/builder:go_default_library",
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
|
@ -3,6 +3,7 @@ package builder
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v4/api/client/builder"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -50,3 +51,11 @@ func WithDatabase(beaconDB db.HeadAccessDatabase) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRegistrationCache uses a cache for the validator registrations instead of a persistent db.
|
||||
func WithRegistrationCache() Option {
|
||||
return func(s *Service) error {
|
||||
s.registrationCache = cache.NewRegistrationCache()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/api/client/builder"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
@ -26,6 +27,7 @@ type BlockBuilder interface {
|
||||
SubmitBlindedBlock(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) (interfaces.ExecutionData, error)
|
||||
GetHeader(ctx context.Context, slot primitives.Slot, parentHash [32]byte, pubKey [48]byte) (builder.SignedBid, error)
|
||||
RegisterValidator(ctx context.Context, reg []*ethpb.SignedValidatorRegistrationV1) error
|
||||
RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error)
|
||||
Configured() bool
|
||||
}
|
||||
|
||||
@ -38,10 +40,11 @@ type config struct {
|
||||
|
||||
// Service defines a service that provides a client for interacting with the beacon chain and MEV relay network.
|
||||
type Service struct {
|
||||
cfg *config
|
||||
c builder.BuilderClient
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
cfg *config
|
||||
c builder.BuilderClient
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
registrationCache *cache.RegistrationCache
|
||||
}
|
||||
|
||||
// NewService instantiates a new service.
|
||||
@ -139,8 +142,12 @@ func (s *Service) RegisterValidator(ctx context.Context, reg []*ethpb.SignedVali
|
||||
return ErrNoBuilder
|
||||
}
|
||||
|
||||
// should be removed if db is removed
|
||||
idxs := make([]primitives.ValidatorIndex, 0)
|
||||
msgs := make([]*ethpb.ValidatorRegistrationV1, 0)
|
||||
|
||||
indexToRegistration := make(map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1)
|
||||
|
||||
valid := make([]*ethpb.SignedValidatorRegistrationV1, 0)
|
||||
for i := 0; i < len(reg); i++ {
|
||||
r := reg[i]
|
||||
@ -154,12 +161,33 @@ func (s *Service) RegisterValidator(ctx context.Context, reg []*ethpb.SignedVali
|
||||
idxs = append(idxs, nx)
|
||||
msgs = append(msgs, r.Message)
|
||||
valid = append(valid, r)
|
||||
indexToRegistration[nx] = r.Message
|
||||
}
|
||||
if err := s.c.RegisterValidator(ctx, valid); err != nil {
|
||||
return errors.Wrap(err, "could not register validator(s)")
|
||||
}
|
||||
|
||||
return s.cfg.beaconDB.SaveRegistrationsByValidatorIDs(ctx, idxs, msgs)
|
||||
if len(indexToRegistration) != len(msgs) {
|
||||
return errors.New("ids and registrations must be the same length")
|
||||
}
|
||||
if s.registrationCache != nil {
|
||||
s.registrationCache.UpdateIndexToRegisteredMap(ctx, indexToRegistration)
|
||||
return nil
|
||||
} else {
|
||||
return s.cfg.beaconDB.SaveRegistrationsByValidatorIDs(ctx, idxs, msgs)
|
||||
}
|
||||
}
|
||||
|
||||
// RegistrationByValidatorID returns either the values from the cache or db.
|
||||
func (s *Service) RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) {
|
||||
if s.registrationCache != nil {
|
||||
return s.registrationCache.RegistrationByIndex(id)
|
||||
} else {
|
||||
if s.cfg == nil || s.cfg.beaconDB == nil {
|
||||
return nil, errors.New("nil beacon db")
|
||||
}
|
||||
return s.cfg.beaconDB.RegistrationByValidatorID(ctx, id)
|
||||
}
|
||||
}
|
||||
|
||||
// Configured returns true if the user has configured a builder client.
|
||||
|
@ -8,6 +8,8 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/client/builder:go_default_library",
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/api/client/builder"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
@ -14,6 +16,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/time/slots"
|
||||
)
|
||||
|
||||
// Config defines a config struct for dependencies into the service.
|
||||
type Config struct {
|
||||
BeaconDB db.HeadAccessDatabase
|
||||
}
|
||||
|
||||
// MockBuilderService to mock builder.
|
||||
type MockBuilderService struct {
|
||||
HasConfigured bool
|
||||
@ -22,8 +29,10 @@ type MockBuilderService struct {
|
||||
ErrSubmitBlindedBlock error
|
||||
Bid *ethpb.SignedBuilderBid
|
||||
BidCapella *ethpb.SignedBuilderBidCapella
|
||||
RegistrationCache *cache.RegistrationCache
|
||||
ErrGetHeader error
|
||||
ErrRegisterValidator error
|
||||
Cfg *Config
|
||||
}
|
||||
|
||||
// Configured for mocking.
|
||||
@ -48,7 +57,7 @@ func (s *MockBuilderService) SubmitBlindedBlock(_ context.Context, _ interfaces.
|
||||
}
|
||||
|
||||
// GetHeader for mocking.
|
||||
func (s *MockBuilderService) GetHeader(ctx context.Context, slot primitives.Slot, hr [32]byte, pb [48]byte) (builder.SignedBid, error) {
|
||||
func (s *MockBuilderService) GetHeader(_ context.Context, slot primitives.Slot, _ [32]byte, _ [48]byte) (builder.SignedBid, error) {
|
||||
if slots.ToEpoch(slot) >= params.BeaconConfig().CapellaForkEpoch {
|
||||
return builder.WrappedSignedBuilderBidCapella(s.BidCapella)
|
||||
}
|
||||
@ -59,6 +68,17 @@ func (s *MockBuilderService) GetHeader(ctx context.Context, slot primitives.Slot
|
||||
return w, s.ErrGetHeader
|
||||
}
|
||||
|
||||
// RegistrationByValidatorID returns either the values from the cache or db.
|
||||
func (s *MockBuilderService) RegistrationByValidatorID(ctx context.Context, id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) {
|
||||
if s.RegistrationCache != nil {
|
||||
return s.RegistrationCache.RegistrationByIndex(id)
|
||||
}
|
||||
if s.Cfg.BeaconDB != nil {
|
||||
return s.Cfg.BeaconDB.RegistrationByValidatorID(ctx, id)
|
||||
}
|
||||
return nil, cache.ErrNotFoundRegistration
|
||||
}
|
||||
|
||||
// RegisterValidator for mocking.
|
||||
func (s *MockBuilderService) RegisterValidator(context.Context, []*ethpb.SignedValidatorRegistrationV1) error {
|
||||
return s.ErrRegisterValidator
|
||||
|
4
beacon-chain/cache/BUILD.bazel
vendored
4
beacon-chain/cache/BUILD.bazel
vendored
@ -17,6 +17,7 @@ go_library(
|
||||
"proposer_indices.go",
|
||||
"proposer_indices_disabled.go", # keep
|
||||
"proposer_indices_type.go",
|
||||
"registration.go",
|
||||
"skip_slot_cache.go",
|
||||
"subnet_ids.go",
|
||||
"sync_committee.go",
|
||||
@ -65,6 +66,7 @@ go_test(
|
||||
"committee_test.go",
|
||||
"payload_id_test.go",
|
||||
"proposer_indices_test.go",
|
||||
"registration_test.go",
|
||||
"skip_slot_cache_test.go",
|
||||
"subnet_ids_test.go",
|
||||
"sync_committee_head_state_test.go",
|
||||
@ -83,7 +85,9 @@ go_test(
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_google_gofuzz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
4
beacon-chain/cache/error.go
vendored
4
beacon-chain/cache/error.go
vendored
@ -1,6 +1,6 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
// ErrNilValueProvided for when we try to put a nil value in a cache.
|
||||
@ -12,4 +12,6 @@ var (
|
||||
// ErrNonExistingSyncCommitteeKey when sync committee key (root) does not exist in cache.
|
||||
ErrNonExistingSyncCommitteeKey = errors.New("does not exist sync committee key")
|
||||
errNotSyncCommitteeIndexPosition = errors.New("not syncCommitteeIndexPosition struct")
|
||||
// ErrNotFoundRegistration when validator registration does not exist in cache.
|
||||
ErrNotFoundRegistration = errors.Wrap(ErrNotFound, "no validator registered")
|
||||
)
|
||||
|
82
beacon-chain/cache/registration.go
vendored
Normal file
82
beacon-chain/cache/registration.go
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/math"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// RegistrationCache is used to store the cached results of an Validator Registration request.
|
||||
// beacon api /eth/v1/validator/register_validator
|
||||
type RegistrationCache struct {
|
||||
indexToRegistration map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewRegistrationCache initializes the map and underlying cache.
|
||||
func NewRegistrationCache() *RegistrationCache {
|
||||
return &RegistrationCache{
|
||||
indexToRegistration: make(map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1),
|
||||
lock: sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
// RegistrationByIndex returns the registration by index in the cache and also removes items in the cache if expired.
|
||||
func (regCache *RegistrationCache) RegistrationByIndex(id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) {
|
||||
regCache.lock.RLock()
|
||||
v, ok := regCache.indexToRegistration[id]
|
||||
if !ok {
|
||||
regCache.lock.RUnlock()
|
||||
return nil, errors.Wrapf(ErrNotFoundRegistration, "validator id %d", id)
|
||||
}
|
||||
isExpired, err := RegistrationTimeStampExpired(v.Timestamp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to check registration expiration")
|
||||
}
|
||||
if isExpired {
|
||||
regCache.lock.RUnlock()
|
||||
regCache.lock.Lock()
|
||||
defer regCache.lock.Unlock()
|
||||
delete(regCache.indexToRegistration, id)
|
||||
log.Warnf("registration for validator index %d expired at unix time %d", id, v.Timestamp)
|
||||
return nil, errors.Wrapf(ErrNotFoundRegistration, "validator id %d", id)
|
||||
}
|
||||
regCache.lock.RUnlock()
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func RegistrationTimeStampExpired(ts uint64) (bool, error) {
|
||||
// safely convert unint64 to int64
|
||||
i, err := math.Int(ts)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
expiryDuration := params.BeaconConfig().RegistrationDuration
|
||||
// registered time + expiration duration < current time = expired
|
||||
return time.Unix(int64(i), 0).Add(expiryDuration).Before(time.Now()), nil
|
||||
}
|
||||
|
||||
// UpdateIndexToRegisteredMap adds or updates values in the cache based on the argument.
|
||||
func (regCache *RegistrationCache) UpdateIndexToRegisteredMap(ctx context.Context, m map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1) {
|
||||
_, span := trace.StartSpan(ctx, "RegistrationCache.UpdateIndexToRegisteredMap")
|
||||
defer span.End()
|
||||
regCache.lock.Lock()
|
||||
defer regCache.lock.Unlock()
|
||||
for key, value := range m {
|
||||
regCache.indexToRegistration[key] = ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: bytesutil.SafeCopyBytes(value.Pubkey),
|
||||
FeeRecipient: bytesutil.SafeCopyBytes(value.FeeRecipient),
|
||||
GasLimit: value.GasLimit,
|
||||
Timestamp: value.Timestamp,
|
||||
}
|
||||
}
|
||||
}
|
82
beacon-chain/cache/registration_test.go
vendored
Normal file
82
beacon-chain/cache/registration_test.go
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func TestRegistrationCache(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
pubkey, err := hexutil.Decode("0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a")
|
||||
require.NoError(t, err)
|
||||
validatorIndex := primitives.ValidatorIndex(1)
|
||||
cache := NewRegistrationCache()
|
||||
m := make(map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1)
|
||||
|
||||
m[validatorIndex] = ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: []byte{},
|
||||
GasLimit: 100,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
Pubkey: pubkey,
|
||||
}
|
||||
cache.UpdateIndexToRegisteredMap(context.Background(), m)
|
||||
reg, err := cache.RegistrationByIndex(validatorIndex)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(reg.Pubkey), string(pubkey))
|
||||
t.Run("Registration expired", func(t *testing.T) {
|
||||
validatorIndex2 := primitives.ValidatorIndex(2)
|
||||
overExpirationPadTime := time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*4) // 4 epochs
|
||||
m[validatorIndex2] = ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: []byte{},
|
||||
GasLimit: 100,
|
||||
Timestamp: uint64(time.Now().Add(-1 * overExpirationPadTime).Unix()),
|
||||
Pubkey: pubkey,
|
||||
}
|
||||
cache.UpdateIndexToRegisteredMap(context.Background(), m)
|
||||
_, err := cache.RegistrationByIndex(validatorIndex2)
|
||||
require.ErrorContains(t, "no validator registered", err)
|
||||
require.LogsContain(t, hook, "expired")
|
||||
})
|
||||
t.Run("Registration close to expiration still passes", func(t *testing.T) {
|
||||
pubkey, err := hexutil.Decode("0x88247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a")
|
||||
require.NoError(t, err)
|
||||
validatorIndex2 := primitives.ValidatorIndex(2)
|
||||
overExpirationPadTime := time.Second * time.Duration((params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*3)-5) // 3 epochs - 5 seconds
|
||||
m[validatorIndex2] = ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: []byte{},
|
||||
GasLimit: 100,
|
||||
Timestamp: uint64(time.Now().Add(-1 * overExpirationPadTime).Unix()),
|
||||
Pubkey: pubkey,
|
||||
}
|
||||
cache.UpdateIndexToRegisteredMap(context.Background(), m)
|
||||
reg, err := cache.RegistrationByIndex(validatorIndex2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(reg.Pubkey), string(pubkey))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_RegistrationTimeStampExpired(t *testing.T) {
|
||||
// expiration set at 3 epochs
|
||||
t.Run("expired registration", func(t *testing.T) {
|
||||
overExpirationPadTime := time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*4) // 4 epochs
|
||||
ts := uint64(time.Now().Add(-1 * overExpirationPadTime).Unix())
|
||||
isExpired, err := RegistrationTimeStampExpired(ts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, isExpired)
|
||||
})
|
||||
t.Run("is not expired registration", func(t *testing.T) {
|
||||
overExpirationPadTime := time.Second * time.Duration((params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*3)-5) // 3 epochs -5 seconds
|
||||
ts := uint64(time.Now().Add(-1 * overExpirationPadTime).Unix())
|
||||
isExpired, err := RegistrationTimeStampExpired(ts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, isExpired)
|
||||
})
|
||||
}
|
@ -3,6 +3,7 @@ package kv
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
@ -910,25 +911,25 @@ func TestStore_RegistrationsByValidatorID(t *testing.T) {
|
||||
ids := []primitives.ValidatorIndex{0, 0, 0}
|
||||
regs := []*ethpb.ValidatorRegistrationV1{{}, {}, {}, {}}
|
||||
require.ErrorContains(t, "ids and registrations must be the same length", db.SaveRegistrationsByValidatorIDs(ctx, ids, regs))
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
ids = []primitives.ValidatorIndex{0, 1, 2}
|
||||
regs = []*ethpb.ValidatorRegistrationV1{
|
||||
{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("a"), 20),
|
||||
GasLimit: 1,
|
||||
Timestamp: 2,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("b"), 48),
|
||||
},
|
||||
{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("c"), 20),
|
||||
GasLimit: 3,
|
||||
Timestamp: 4,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("d"), 48),
|
||||
},
|
||||
{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("e"), 20),
|
||||
GasLimit: 5,
|
||||
Timestamp: 6,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("f"), 48),
|
||||
},
|
||||
}
|
||||
@ -938,7 +939,7 @@ func TestStore_RegistrationsByValidatorID(t *testing.T) {
|
||||
require.DeepEqual(t, ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("a"), 20),
|
||||
GasLimit: 1,
|
||||
Timestamp: 2,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("b"), 48),
|
||||
}, f)
|
||||
f, err = db.RegistrationByValidatorID(ctx, 1)
|
||||
@ -946,7 +947,7 @@ func TestStore_RegistrationsByValidatorID(t *testing.T) {
|
||||
require.DeepEqual(t, ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("c"), 20),
|
||||
GasLimit: 3,
|
||||
Timestamp: 4,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("d"), 48),
|
||||
}, f)
|
||||
f, err = db.RegistrationByValidatorID(ctx, 2)
|
||||
@ -954,7 +955,7 @@ func TestStore_RegistrationsByValidatorID(t *testing.T) {
|
||||
require.DeepEqual(t, ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("e"), 20),
|
||||
GasLimit: 5,
|
||||
Timestamp: 6,
|
||||
Timestamp: uint64(timestamp),
|
||||
Pubkey: bytesutil.PadTo([]byte("f"), 48),
|
||||
}, f)
|
||||
_, err = db.RegistrationByValidatorID(ctx, 3)
|
||||
|
@ -249,7 +249,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
}
|
||||
|
||||
log.Debugln("Registering builder service")
|
||||
if err := beacon.registerBuilderService(); err != nil {
|
||||
if err := beacon.registerBuilderService(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -961,7 +961,7 @@ func (b *BeaconNode) registerValidatorMonitorService() error {
|
||||
return b.services.RegisterService(svc)
|
||||
}
|
||||
|
||||
func (b *BeaconNode) registerBuilderService() error {
|
||||
func (b *BeaconNode) registerBuilderService(cliCtx *cli.Context) error {
|
||||
var chainService *blockchain.Service
|
||||
if err := b.services.FetchService(&chainService); err != nil {
|
||||
return err
|
||||
@ -970,6 +970,9 @@ func (b *BeaconNode) registerBuilderService() error {
|
||||
opts := append(b.serviceFlagOpts.builderOpts,
|
||||
builder.WithHeadFetcher(chainService),
|
||||
builder.WithDatabase(b.db))
|
||||
if cliCtx.Bool(flags.EnableRegistrationCache.Name) {
|
||||
opts = append(opts, builder.WithRegistrationCache())
|
||||
}
|
||||
svc, err := builder.NewService(b.ctx, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -744,6 +744,7 @@ func (vs *Server) PrepareBeaconProposer(
|
||||
if err := vs.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, validatorIndices, feeRecipients); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not save fee recipients: %v", err)
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"validatorIndices": validatorIndices,
|
||||
}).Info("Updated fee recipient addresses for validator indices")
|
||||
|
@ -776,7 +776,6 @@ func TestProduceBlockV2(t *testing.T) {
|
||||
|
||||
resp, err := server.ProduceBlockV2(ctx, ðpbv1.ProduceBlockRequest{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, ethpbv2.Version_CAPELLA, resp.Version)
|
||||
containerBlock, ok := resp.Data.Block.(*ethpbv2.BeaconBlockContainerV2_CapellaBlock)
|
||||
require.Equal(t, true, ok)
|
||||
|
@ -69,7 +69,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
FinalizationFetcher: &blockchainTest.ChainService{},
|
||||
BeaconDB: beaconDB,
|
||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true},
|
||||
BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true, Cfg: &builderTest.Config{BeaconDB: beaconDB}},
|
||||
}
|
||||
|
||||
t.Run("No builder configured. Use local block", func(t *testing.T) {
|
||||
@ -84,7 +84,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
blk, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, vs.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{blk.Block().ProposerIndex()},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), Pubkey: make([]byte, fieldparams.BLSPubkeyLength)}}))
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), Timestamp: uint64(time.Now().Unix()), Pubkey: make([]byte, fieldparams.BLSPubkeyLength)}}))
|
||||
ti, err := slots.ToTime(uint64(time.Now().Unix()), 0)
|
||||
require.NoError(t, err)
|
||||
sk, err := bls.RandKey()
|
||||
@ -119,6 +119,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
vs.BlockBuilder = &builderTest.MockBuilderService{
|
||||
BidCapella: sBid,
|
||||
HasConfigured: true,
|
||||
Cfg: &builderTest.Config{BeaconDB: beaconDB},
|
||||
}
|
||||
wb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
|
||||
require.NoError(t, err)
|
||||
@ -136,7 +137,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
blk, err := blocks.NewSignedBeaconBlock(util.NewBlindedBeaconBlockCapella())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, vs.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{blk.Block().ProposerIndex()},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), Pubkey: make([]byte, fieldparams.BLSPubkeyLength)}}))
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), Timestamp: uint64(time.Now().Unix()), Pubkey: make([]byte, fieldparams.BLSPubkeyLength)}}))
|
||||
ti, err := slots.ToTime(uint64(time.Now().Unix()), 0)
|
||||
require.NoError(t, err)
|
||||
sk, err := bls.RandKey()
|
||||
@ -174,6 +175,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
vs.BlockBuilder = &builderTest.MockBuilderService{
|
||||
BidCapella: sBid,
|
||||
HasConfigured: true,
|
||||
Cfg: &builderTest.Config{BeaconDB: beaconDB},
|
||||
}
|
||||
wb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
|
||||
require.NoError(t, err)
|
||||
@ -219,6 +221,7 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
vs.BlockBuilder = &builderTest.MockBuilderService{
|
||||
ErrGetHeader: errors.New("fault"),
|
||||
HasConfigured: true,
|
||||
Cfg: &builderTest.Config{BeaconDB: beaconDB},
|
||||
}
|
||||
vs.ExecutionEngineCaller = &powtesting.EngineClient{PayloadIDBytes: id, ExecutionPayloadCapella: &v1.ExecutionPayloadCapella{BlockNumber: 4}, BlockValue: 0}
|
||||
require.NoError(t, vs.setExecutionData(context.Background(), blk, capellaTransitionState))
|
||||
@ -227,7 +230,6 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
require.Equal(t, uint64(4), e.BlockNumber()) // Local block
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_getPayloadHeader(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
bc := params.BeaconConfig()
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
@ -36,12 +37,12 @@ func (vs *Server) canUseBuilder(ctx context.Context, slot primitives.Slot, idx p
|
||||
|
||||
// validatorRegistered returns true if validator with index `id` was previously registered in the database.
|
||||
func (vs *Server) validatorRegistered(ctx context.Context, id primitives.ValidatorIndex) (bool, error) {
|
||||
if vs.BeaconDB == nil {
|
||||
return false, errors.New("nil beacon db")
|
||||
if vs.BlockBuilder == nil {
|
||||
return false, nil
|
||||
}
|
||||
_, err := vs.BeaconDB.RegistrationByValidatorID(ctx, id)
|
||||
_, err := vs.BlockBuilder.RegistrationByValidatorID(ctx, id)
|
||||
switch {
|
||||
case errors.Is(err, kv.ErrNotFoundFeeRecipient):
|
||||
case errors.Is(err, kv.ErrNotFoundFeeRecipient), errors.Is(err, cache.ErrNotFoundRegistration):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, err
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
blockchainTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/builder"
|
||||
testing2 "github.com/prysmaticlabs/prysm/v4/beacon-chain/builder/testing"
|
||||
dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
@ -71,22 +72,28 @@ func TestServer_circuitBreakBuilder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_validatorRegistered(t *testing.T) {
|
||||
proposerServer := &Server{}
|
||||
b, err := builder.NewService(context.Background())
|
||||
require.NoError(t, err)
|
||||
proposerServer := &Server{
|
||||
BlockBuilder: b,
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
reg, err := proposerServer.validatorRegistered(ctx, 0)
|
||||
require.ErrorContains(t, "nil beacon db", err)
|
||||
require.Equal(t, false, reg)
|
||||
|
||||
proposerServer.BeaconDB = dbTest.SetupDB(t)
|
||||
db := dbTest.SetupDB(t)
|
||||
realBuilder, err := builder.NewService(context.Background(), builder.WithDatabase(db))
|
||||
require.NoError(t, err)
|
||||
proposerServer.BlockBuilder = realBuilder
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reg)
|
||||
|
||||
f := bytesutil.PadTo([]byte{}, fieldparams.FeeRecipientLength)
|
||||
p := bytesutil.PadTo([]byte{}, fieldparams.BLSPubkeyLength)
|
||||
require.NoError(t, proposerServer.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{0, 1},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: f, Pubkey: p}, {FeeRecipient: f, Pubkey: p}}))
|
||||
require.NoError(t, db.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{0, 1},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: f, Timestamp: uint64(time.Now().Unix()), Pubkey: p}, {FeeRecipient: f, Timestamp: uint64(time.Now().Unix()), Pubkey: p}}))
|
||||
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
@ -94,6 +101,7 @@ func TestServer_validatorRegistered(t *testing.T) {
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, reg)
|
||||
|
||||
}
|
||||
|
||||
func TestServer_canUseBuilder(t *testing.T) {
|
||||
@ -105,9 +113,6 @@ func TestServer_canUseBuilder(t *testing.T) {
|
||||
reg, err := proposerServer.canUseBuilder(context.Background(), 0, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reg)
|
||||
proposerServer.BlockBuilder = &testing2.MockBuilderService{
|
||||
HasConfigured: true,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
@ -116,20 +121,21 @@ func TestServer_canUseBuilder(t *testing.T) {
|
||||
reg, err = proposerServer.canUseBuilder(ctx, params.BeaconConfig().MaxBuilderConsecutiveMissedSlots+1, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reg)
|
||||
db := dbTest.SetupDB(t)
|
||||
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 0)
|
||||
require.ErrorContains(t, "nil beacon db", err)
|
||||
require.Equal(t, false, reg)
|
||||
proposerServer.BlockBuilder = &testing2.MockBuilderService{
|
||||
HasConfigured: true,
|
||||
Cfg: &testing2.Config{BeaconDB: db},
|
||||
}
|
||||
|
||||
proposerServer.BeaconDB = dbTest.SetupDB(t)
|
||||
reg, err = proposerServer.canUseBuilder(ctx, 1, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reg)
|
||||
|
||||
f := bytesutil.PadTo([]byte{}, fieldparams.FeeRecipientLength)
|
||||
p := bytesutil.PadTo([]byte{}, fieldparams.BLSPubkeyLength)
|
||||
require.NoError(t, proposerServer.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{0},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: f, Pubkey: p}}))
|
||||
require.NoError(t, db.SaveRegistrationsByValidatorIDs(ctx, []primitives.ValidatorIndex{0},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: f, Timestamp: uint64(time.Now().Unix()), Pubkey: p}}))
|
||||
|
||||
reg, err = proposerServer.canUseBuilder(ctx, params.BeaconConfig().MaxBuilderConsecutiveMissedSlots-1, 0)
|
||||
require.NoError(t, err)
|
||||
|
@ -3,8 +3,6 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -94,7 +92,7 @@ var (
|
||||
HTTPModules = &cli.StringFlag{
|
||||
Name: "http-modules",
|
||||
Usage: "Comma-separated list of API module names. Possible values: `" + PrysmAPIModule + `,` + EthAPIModule + "`.",
|
||||
Value: strings.Join([]string{PrysmAPIModule, EthAPIModule}, ","),
|
||||
Value: PrysmAPIModule + `,` + EthAPIModule,
|
||||
}
|
||||
// DisableGRPCGateway for JSON-HTTP requests to the beacon node.
|
||||
DisableGRPCGateway = &cli.BoolFlag{
|
||||
@ -204,6 +202,11 @@ var (
|
||||
Usage: "Sets the maximum number of headers that a deposit log query can fetch.",
|
||||
Value: uint64(1000),
|
||||
}
|
||||
// EnableRegistrationCache a temporary flag for enabling the validator registration cache instead of db.
|
||||
EnableRegistrationCache = &cli.BoolFlag{
|
||||
Name: "enable-registration-cache",
|
||||
Usage: "A temporary flag for enabling the validator registration cache instead of persisting in db. The cache will clear on restart.",
|
||||
}
|
||||
// WeakSubjectivityCheckpoint defines the weak subjectivity checkpoint the node must sync through to defend against long range attacks.
|
||||
WeakSubjectivityCheckpoint = &cli.StringFlag{
|
||||
Name: "weak-subjectivity-checkpoint",
|
||||
|
@ -58,6 +58,7 @@ var appFlags = []cli.Flag{
|
||||
flags.InteropGenesisTimeFlag,
|
||||
flags.SlotsPerArchivedPoint,
|
||||
flags.EnableDebugRPCEndpoints,
|
||||
flags.EnableRegistrationCache,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.HistoricalSlasherNode,
|
||||
flags.ChainID,
|
||||
|
@ -113,6 +113,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.BlockBatchLimit,
|
||||
flags.BlockBatchLimitBurstFactor,
|
||||
flags.EnableDebugRPCEndpoints,
|
||||
flags.EnableRegistrationCache,
|
||||
flags.SubscribeToAllSubnets,
|
||||
flags.HistoricalSlasherNode,
|
||||
flags.ChainID,
|
||||
|
@ -209,6 +209,8 @@ type BeaconChainConfig struct {
|
||||
MaxBuilderEpochMissedSlots primitives.Slot // MaxBuilderEpochMissedSlots is defines the number of total skip slot (per epoch rolling windows) to fallback from using relay/builder to local execution engine for block construction.
|
||||
LocalBlockValueBoost uint64 // LocalBlockValueBoost is the value boost for local block construction. This is used to prioritize local block construction over relay/builder block construction.
|
||||
|
||||
// Mev validator registration
|
||||
RegistrationDuration time.Duration // RegistrationDuration is the duration a validator registration is valid for.
|
||||
// Execution engine timeout value
|
||||
ExecutionEngineTimeoutValue uint64 // ExecutionEngineTimeoutValue defines the seconds to wait before timing out engine endpoints with execution payload execution semantics (newPayload, forkchoiceUpdated).
|
||||
}
|
||||
|
@ -257,7 +257,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
// Mevboost circuit breaker
|
||||
MaxBuilderConsecutiveMissedSlots: 3,
|
||||
MaxBuilderEpochMissedSlots: 5,
|
||||
|
||||
// Mev validator registration duration before expiration
|
||||
RegistrationDuration: 12 * 32 * 3 * time.Second, // defaults to 3 Epochs
|
||||
// Execution engine timeout value
|
||||
ExecutionEngineTimeoutValue: 8, // 8 seconds default based on: https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#core
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user