Compare commits

...

18 Commits

Author SHA1 Message Date
Preston Van Loon
aa7d0df7ff Fix metric name from PR #12430 (#12445)
* Fix metric name from PR #12430

* @potuz can't spell 'unknown'

---------

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
(cherry picked from commit 7fe935e94d)
2023-05-22 12:45:38 -05:00
Nishant Das
0a213d70e8 disable it (#12438)
(cherry picked from commit 51bde7a845)
2023-05-22 11:24:43 -05:00
Potuz
b84dd40ba9 Use forkchoice to validate sync messages faster (#12430)
* Use forkchoice to validate sync messages faster

* add metric
2023-05-19 14:47:39 +00:00
kasey
aeaa72fdc2 fix deadlock between monitor service and init-sync (#12427)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2023-05-18 18:35:06 +00:00
kasey
ddc1e48e05 Revert "BeaconBlocksByRange and BlobSidecarsByRange consistency (#123… (#12426)
This reverts commit 73e4bdccbb.

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2023-05-18 18:01:26 +00:00
Nishant Das
f91159337b Fix Migration Of State (#12423) 2023-05-18 13:18:56 +00:00
Potuz
537236e1c9 Add aggregation metrics (#12417) 2023-05-17 12:18:59 -07:00
kasey
73e4bdccbb BeaconBlocksByRange and BlobSidecarsByRange consistency (#12383)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2023-05-17 12:16:10 +00:00
Potuz
f54bd64bdd Default aggregation ticker times (#12412)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2023-05-16 19:38:44 +00:00
james-prysm
d907cae595 persistent validator settings in validator client (#12354)
* WIP

* improving proposer settings store

* WIP persistent validator settings

* WIP persistent validator settings

* changing visibility level

* fixing some deepsource issues

* fixing more deepsource issues

* fixing json marshalling

* fix linting

* fixing tests

* fixing more tests

* fixing more tests

* fixing more tests

* fixing linting

* WIP fixing unit tests

* fixing remaining db tests

* converting json to protobuf

* fixing e2e

* k8s yaml library is used directly

* fixing linting

* fixing broken unit test

* reverting changes on e2e

* fixing linting

* fixing deepsource issue

* resolving some internal comments

* resolving some comments and adding more tests

* adding more unit tests

* gaz

* fixing flaking test

* fixing unit test contamination

* fixing deepsource issue

* resolving review item

* gaz
2023-05-16 14:08:49 -05:00
Potuz
be23773924 Don't use max cover on unaggregated atts nor check subgroup of validated signatures (#12350)
* Don't use max cover on unnaggregated atts

* Do not validate signature on the attestation package

* separate nil error checks

* fix unit tests
2023-05-16 17:06:26 +00:00
terencechain
29f6de1e96 Flip build block parallel feature flag (#12408) 2023-05-16 08:43:15 -07:00
Potuz
955a21fea4 revert revert of f6764fe62b (#12399) 2023-05-16 11:50:02 +00:00
Preston Van Loon
b4f1fea029 CI: fix docker image tagging (#12407) 2023-05-16 02:10:23 +00:00
kasey
f1b88d005d fix broken slasher service init (#12405)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2023-05-15 17:00:29 -05:00
Preston Van Loon
ee612d958a Update discord invite (#12403) 2023-05-15 13:54:19 +00:00
Nishant Das
09e22538f9 Support Capella Blocks for Tool (#12402)
* fix it

* fix it
2023-05-15 17:59:02 +08:00
terencechain
3b9e974a45 Add epoch and root to not a checkpt in forkchoice log (#12400)
* Add epoch number and root in not a checkpt in forkchoice log

* Update beacon-chain/blockchain/process_attestation_helpers.go

Co-authored-by: Nishant Das <nishdas93@gmail.com>

* Fix test

* Fix typo

---------

Co-authored-by: Nishant Das <nishdas93@gmail.com>
2023-05-14 06:02:36 +00:00
67 changed files with 1997 additions and 422 deletions

View File

@@ -4,14 +4,14 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/prysmaticlabs/prysm)](https://goreportcard.com/report/github.com/prysmaticlabs/prysm)
[![Consensus_Spec_Version 1.3.0](https://img.shields.io/badge/Consensus%20Spec%20Version-v1.3.0-blue.svg)](https://github.com/ethereum/consensus-specs/tree/v1.3.0)
[![Execution_API_Version 1.0.0-beta.2](https://img.shields.io/badge/Execution%20API%20Version-v1.0.0.beta.2-blue.svg)](https://github.com/ethereum/execution-apis/tree/v1.0.0-beta.2/src/engine)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/CTYGPUJ)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/prysmaticlabs)
[![GitPOAP Badge](https://public-api.gitpoap.io/v1/repo/prysmaticlabs/prysm/badge)](https://www.gitpoap.io/gh/prysmaticlabs/prysm)
This is the core repository for Prysm, a [Golang](https://golang.org/) implementation of the [Ethereum Consensus](https://ethereum.org/en/eth2/) specification, developed by [Prysmatic Labs](https://prysmaticlabs.com). See the [Changelog](https://github.com/prysmaticlabs/prysm/releases) for details of the latest releases and upcoming breaking changes.
### Getting Started
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by our [Discord](https://discord.gg/CTYGPUJ).
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by our [Discord](https://discord.gg/prysmaticlabs).
### Staking on Mainnet

View File

@@ -69,7 +69,7 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (stat
return nil, errors.Wrap(err, "could not check checkpoint condition in forkchoice")
}
if !ok {
return nil, ErrNotCheckpoint
return nil, errors.Wrap(ErrNotCheckpoint, fmt.Sprintf("epoch %d root %#x", c.Epoch, c.Root))
}
// Fallback to state regeneration.

View File

@@ -180,7 +180,7 @@ func TestStore_SaveCheckpointState(t *testing.T) {
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Root: bytesutil.PadTo([]byte{'B'}, fieldparams.RootLength)}))
s2, err := service.getAttPreState(ctx, cp2)
require.ErrorIs(t, ErrNotCheckpoint, err)
require.ErrorContains(t, "epoch 2 root 0x4200000000000000000000000000000000000000000000000000000000000000: not a checkpoint in forkchoice", err)
st, root, err = prepareForkchoiceState(ctx, 33, [32]byte(cp2.Root), [32]byte(cp1.Root), [32]byte{'R'}, cp2, cp2)
require.NoError(t, err)

View File

@@ -130,9 +130,15 @@ func performValidatorStateMigration(ctx context.Context, bar *progressbar.Progre
return err
}
item := enc
if hasAltairKey(item) {
switch {
case hasAltairKey(enc):
item = item[len(altairKey):]
case hasBellatrixKey(enc):
item = item[len(bellatrixKey):]
case hasCapellaKey(enc):
item = item[len(capellaKey):]
}
detector, err := detect.FromState(item)
if err != nil {
return err
@@ -165,9 +171,14 @@ func performValidatorStateMigration(ctx context.Context, bar *progressbar.Progre
return err
}
var stateBytes []byte
if hasAltairKey(enc) {
switch {
case hasAltairKey(enc):
stateBytes = snappy.Encode(nil, append(altairKey, rawObj...))
} else {
case hasBellatrixKey(enc):
stateBytes = snappy.Encode(nil, append(bellatrixKey, rawObj...))
case hasCapellaKey(enc):
stateBytes = snappy.Encode(nil, append(capellaKey, rawObj...))
default:
stateBytes = snappy.Encode(nil, rawObj)
}
if stateErr := stateBkt.Put(keys[index], stateBytes); stateErr != nil {

View File

@@ -313,3 +313,217 @@ func Test_migrateAltairStateValidators(t *testing.T) {
})
}
}
func Test_migrateBellatrixStateValidators(t *testing.T) {
tests := []struct {
name string
setup func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
eval func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
}{
{
name: "migrates validators and adds them to new buckets",
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// create some new buckets that should be present for this migration
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
assert.NoError(t, err)
_, err = tx.CreateBucketIfNotExists(blockRootValidatorHashesBucket)
assert.NoError(t, err)
return nil
})
assert.NoError(t, err)
},
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// check whether the new buckets are present
err := dbStore.db.View(func(tx *bbolt.Tx) error {
valBkt := tx.Bucket(stateValidatorsBucket)
assert.NotNil(t, valBkt)
idxBkt := tx.Bucket(blockRootValidatorHashesBucket)
assert.NotNil(t, idxBkt)
return nil
})
assert.NoError(t, err)
// check if the migration worked
blockRoot := [32]byte{'A'}
rcvdState, err := dbStore.State(context.Background(), blockRoot)
assert.NoError(t, err)
require.DeepSSZEqual(t, rcvdState.ToProtoUnsafe(), state.ToProtoUnsafe(), "saved state with validators and retrieved state are not matching")
// find hashes of the validators that are set as part of the state
var hashes []byte
var individualHashes [][]byte
for _, val := range vals {
hash, hashErr := val.HashTreeRoot()
assert.NoError(t, hashErr)
hashes = append(hashes, hash[:]...)
individualHashes = append(individualHashes, hash[:])
}
// check if all the validators that were in the state, are stored properly in the validator bucket
pbState, err := state_native.ProtobufBeaconStateBellatrix(rcvdState.ToProtoUnsafe())
assert.NoError(t, err)
validatorsFoundCount := 0
for _, val := range pbState.Validators {
hash, hashErr := val.HashTreeRoot()
assert.NoError(t, hashErr)
found := false
for _, h := range individualHashes {
if bytes.Equal(hash[:], h) {
found = true
}
}
require.Equal(t, true, found)
validatorsFoundCount++
}
require.Equal(t, len(vals), validatorsFoundCount)
// check if the state validator indexes are stored properly
err = dbStore.db.View(func(tx *bbolt.Tx) error {
rcvdValhashBytes := tx.Bucket(blockRootValidatorHashesBucket).Get(blockRoot[:])
rcvdValHashes, sErr := snappy.Decode(nil, rcvdValhashBytes)
assert.NoError(t, sErr)
require.DeepEqual(t, hashes, rcvdValHashes)
return nil
})
assert.NoError(t, err)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dbStore := setupDB(t)
// add a state with the given validators
vals := validators(10)
blockRoot := [32]byte{'A'}
st, _ := util.DeterministicGenesisStateBellatrix(t, 20)
err := st.SetFork(&v1alpha1.Fork{
PreviousVersion: params.BeaconConfig().AltairForkVersion,
CurrentVersion: params.BeaconConfig().BellatrixForkVersion,
Epoch: 0,
})
require.NoError(t, err)
assert.NoError(t, st.SetSlot(100))
assert.NoError(t, st.SetValidators(vals))
assert.NoError(t, dbStore.SaveState(context.Background(), st, blockRoot))
// enable historical state representation flag to test this
resetCfg := features.InitWithReset(&features.Flags{
EnableHistoricalSpaceRepresentation: true,
})
defer resetCfg()
tt.setup(t, dbStore, st, vals)
assert.NoError(t, migrateStateValidators(context.Background(), dbStore.db), "migrateArchivedIndex(tx) error")
tt.eval(t, dbStore, st, vals)
})
}
}
func Test_migrateCapellaStateValidators(t *testing.T) {
tests := []struct {
name string
setup func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
eval func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
}{
{
name: "migrates validators and adds them to new buckets",
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// create some new buckets that should be present for this migration
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
assert.NoError(t, err)
_, err = tx.CreateBucketIfNotExists(blockRootValidatorHashesBucket)
assert.NoError(t, err)
return nil
})
assert.NoError(t, err)
},
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
// check whether the new buckets are present
err := dbStore.db.View(func(tx *bbolt.Tx) error {
valBkt := tx.Bucket(stateValidatorsBucket)
assert.NotNil(t, valBkt)
idxBkt := tx.Bucket(blockRootValidatorHashesBucket)
assert.NotNil(t, idxBkt)
return nil
})
assert.NoError(t, err)
// check if the migration worked
blockRoot := [32]byte{'A'}
rcvdState, err := dbStore.State(context.Background(), blockRoot)
assert.NoError(t, err)
require.DeepSSZEqual(t, rcvdState.ToProtoUnsafe(), state.ToProtoUnsafe(), "saved state with validators and retrieved state are not matching")
// find hashes of the validators that are set as part of the state
var hashes []byte
var individualHashes [][]byte
for _, val := range vals {
hash, hashErr := val.HashTreeRoot()
assert.NoError(t, hashErr)
hashes = append(hashes, hash[:]...)
individualHashes = append(individualHashes, hash[:])
}
// check if all the validators that were in the state, are stored properly in the validator bucket
pbState, err := state_native.ProtobufBeaconStateCapella(rcvdState.ToProtoUnsafe())
assert.NoError(t, err)
validatorsFoundCount := 0
for _, val := range pbState.Validators {
hash, hashErr := val.HashTreeRoot()
assert.NoError(t, hashErr)
found := false
for _, h := range individualHashes {
if bytes.Equal(hash[:], h) {
found = true
}
}
require.Equal(t, true, found)
validatorsFoundCount++
}
require.Equal(t, len(vals), validatorsFoundCount)
// check if the state validator indexes are stored properly
err = dbStore.db.View(func(tx *bbolt.Tx) error {
rcvdValhashBytes := tx.Bucket(blockRootValidatorHashesBucket).Get(blockRoot[:])
rcvdValHashes, sErr := snappy.Decode(nil, rcvdValhashBytes)
assert.NoError(t, sErr)
require.DeepEqual(t, hashes, rcvdValHashes)
return nil
})
assert.NoError(t, err)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dbStore := setupDB(t)
// add a state with the given validators
vals := validators(10)
blockRoot := [32]byte{'A'}
st, _ := util.DeterministicGenesisStateCapella(t, 20)
err := st.SetFork(&v1alpha1.Fork{
PreviousVersion: params.BeaconConfig().BellatrixForkVersion,
CurrentVersion: params.BeaconConfig().CapellaForkVersion,
Epoch: 0,
})
require.NoError(t, err)
assert.NoError(t, st.SetSlot(100))
assert.NoError(t, st.SetValidators(vals))
assert.NoError(t, dbStore.SaveState(context.Background(), st, blockRoot))
// enable historical state representation flag to test this
resetCfg := features.InitWithReset(&features.Flags{
EnableHistoricalSpaceRepresentation: true,
})
defer resetCfg()
tt.setup(t, dbStore, st, vals)
assert.NoError(t, migrateStateValidators(context.Background(), dbStore.db), "migrateArchivedIndex(tx) error")
tt.eval(t, dbStore, st, vals)
})
}
}

View File

@@ -114,19 +114,11 @@ func (s *Service) Start() {
"ValidatorIndices": tracked,
}).Info("Starting service")
stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)
go s.run(stateChannel, stateSub)
go s.run()
}
// run waits until the beacon is synced and starts the monitoring system.
func (s *Service) run(stateChannel chan *feed.Event, stateSub event.Subscription) {
if stateChannel == nil {
log.Error("State state is nil")
return
}
func (s *Service) run() {
if err := s.waitForSync(s.config.InitialSyncComplete); err != nil {
log.WithError(err)
return
@@ -154,6 +146,8 @@ func (s *Service) run(stateChannel chan *feed.Event, stateSub event.Subscription
s.isLogging = true
s.Unlock()
stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)
s.monitorRoutine(stateChannel, stateSub)
}

View File

@@ -271,11 +271,9 @@ func TestWaitForSyncCanceled(t *testing.T) {
func TestRun(t *testing.T) {
hook := logTest.NewGlobal()
s := setupService(t)
stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)
go func() {
s.run(stateChannel, stateSub)
s.run()
}()
close(s.config.InitialSyncComplete)

View File

@@ -581,7 +581,8 @@ func (b *BeaconNode) fetchBuilderService() *builder.Service {
func (b *BeaconNode) registerAttestationPool() error {
s, err := attestations.NewService(b.ctx, &attestations.Config{
Pool: b.attestationPool,
Pool: b.attestationPool,
InitialSyncComplete: b.initialSyncComplete,
})
if err != nil {
return errors.Wrap(err, "could not register atts pool service")
@@ -742,6 +743,7 @@ func (b *BeaconNode) registerSlasherService() error {
SlashingPoolInserter: b.slashingsPool,
SyncChecker: syncService,
HeadStateFetcher: chainService,
ClockWaiter: b.clockWaiter,
})
if err != nil {
return err

View File

@@ -18,6 +18,7 @@ go_library(
deps = [
"//beacon-chain/operations/attestations/kv:go_default_library",
"//cache/lru:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/hash:go_default_library",

View File

@@ -53,27 +53,25 @@ func (c *AttCaches) aggregateUnaggregatedAttestations(ctx context.Context, unagg
// Track the unaggregated attestations that aren't able to aggregate.
leftOverUnaggregatedAtt := make(map[[32]byte]bool)
for _, atts := range attsByDataRoot {
aggregatedAtts := make([]*ethpb.Attestation, 0, len(atts))
processedAtts, err := attaggregation.Aggregate(atts)
aggregated, err := attaggregation.AggregateDisjointOneBitAtts(atts)
if err != nil {
return err
return errors.Wrap(err, "could not aggregate unaggregated attestations")
}
for _, att := range processedAtts {
if helpers.IsAggregated(att) {
aggregatedAtts = append(aggregatedAtts, att)
} else {
h, err := hashFn(att)
if err != nil {
return err
}
leftOverUnaggregatedAtt[h] = true
if aggregated == nil {
return errors.New("could not aggregate unaggregated attestations")
}
if helpers.IsAggregated(aggregated) {
if err := c.SaveAggregatedAttestations([]*ethpb.Attestation{aggregated}); err != nil {
return err
}
}
if err := c.SaveAggregatedAttestations(aggregatedAtts); err != nil {
return err
} else {
h, err := hashFn(aggregated)
if err != nil {
return err
}
leftOverUnaggregatedAtt[h] = true
}
}
// Remove the unaggregated attestations from the pool that were successfully aggregated.
for _, att := range unaggregatedAtts {
h, err := hashFn(att)
@@ -87,7 +85,6 @@ func (c *AttCaches) aggregateUnaggregatedAttestations(ctx context.Context, unagg
return err
}
}
return nil
}

View File

@@ -30,6 +30,20 @@ var (
Name: "expired_block_atts_total",
Help: "The number of expired and deleted block attestations in the pool.",
})
batchForkChoiceAttsT1 = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "aggregate_attestations_t1",
Help: "Captures times of attestation aggregation in milliseconds during the first interval per slot",
Buckets: []float64{100, 200, 500, 1000, 1500, 2000, 2500, 3500},
},
)
batchForkChoiceAttsT2 = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "aggregate_attestations_t2",
Help: "Captures times of attestation aggregation in milliseconds during the second interval per slot",
Buckets: []float64{10, 40, 100, 200, 600},
},
)
)
func (s *Service) updateMetrics() {

View File

@@ -7,6 +7,8 @@ import (
"time"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/crypto/hash"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
attaggregation "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/attestation/aggregation/attestations"
@@ -14,20 +16,34 @@ import (
"go.opencensus.io/trace"
)
// Prepare attestations for fork choice three times per slot.
var prepareForkChoiceAttsPeriod = slots.DivideSlotBy(3 /* times-per-slot */)
// This prepares fork choice attestations by running batchForkChoiceAtts
// every prepareForkChoiceAttsPeriod.
func (s *Service) prepareForkChoiceAtts() {
ticker := time.NewTicker(prepareForkChoiceAttsPeriod)
defer ticker.Stop()
intervals := features.Get().AggregateIntervals
slotDuration := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
// Adjust intervals for networks with a lower slot duration (Hive, e2e, etc)
for {
if intervals[len(intervals)-1] >= slotDuration {
for i, offset := range intervals {
intervals[i] = offset / 2
}
} else {
break
}
}
ticker := slots.NewSlotTickerWithIntervals(time.Unix(int64(s.genesisTime), 0), intervals[:])
for {
select {
case <-ticker.C:
case <-ticker.C():
t := time.Now()
if err := s.batchForkChoiceAtts(s.ctx); err != nil {
log.WithError(err).Error("Could not prepare attestations for fork choice")
}
if slots.TimeIntoSlot(s.genesisTime) < intervals[1] {
batchForkChoiceAttsT1.Observe(float64(time.Since(t).Milliseconds()))
} else if slots.TimeIntoSlot(s.genesisTime) < intervals[2] {
batchForkChoiceAttsT2.Observe(float64(time.Since(t).Milliseconds()))
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting routine")
return

View File

@@ -5,6 +5,7 @@ package attestations
import (
"context"
"errors"
"time"
lru "github.com/hashicorp/golang-lru"
@@ -26,8 +27,9 @@ type Service struct {
// Config options for the service.
type Config struct {
Pool Pool
pruneInterval time.Duration
Pool Pool
pruneInterval time.Duration
InitialSyncComplete chan struct{}
}
// NewService instantiates a new attestation pool service instance that will
@@ -51,10 +53,24 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
// Start an attestation pool service's main event loop.
func (s *Service) Start() {
if err := s.waitForSync(s.cfg.InitialSyncComplete); err != nil {
log.WithError(err).Error("failed to wait for initial sync")
return
}
go s.prepareForkChoiceAtts()
go s.pruneAttsPool()
}
// waitForSync waits until the beacon node is synced to the latest head.
func (s *Service) waitForSync(syncChan chan struct{}) error {
select {
case <-syncChan:
return nil
case <-s.ctx.Done():
return errors.New("context closed, exiting goroutine")
}
}
// Stop the beacon block attestation pool service's main event loop
// and associated goroutines.
func (s *Service) Stop() error {

View File

@@ -30,8 +30,22 @@ func (s *Store) SaveSyncCommitteeMessage(msg *ethpb.SyncCommitteeMessage) error
return errors.New("not typed []ethpb.SyncCommitteeMessage")
}
messages = append(messages, copied)
savedSyncCommitteeMessageTotal.Inc()
idx := -1
for i, msg := range messages {
if msg.ValidatorIndex == copied.ValidatorIndex {
idx = i
break
}
}
if idx >= 0 {
// Override the existing messages with a new one
messages[idx] = copied
} else {
// Append the new message
messages = append(messages, copied)
savedSyncCommitteeMessageTotal.Inc()
}
return s.messageCache.Push(&queue.Item{
Key: syncCommitteeKey(msg.Slot),
Value: messages,

View File

@@ -55,6 +55,7 @@ go_library(
"//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//cmd/beacon-chain/flags:go_default_library",
"//config/features:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/wrapper:go_default_library",

View File

@@ -6,12 +6,14 @@ import (
"net"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/muxer/mplex"
"github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/config/features"
ecdsaprysm "github.com/prysmaticlabs/prysm/v4/crypto/ecdsa"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
)
@@ -99,6 +101,9 @@ func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) []libp2p.Opt
}
// Disable Ping Service.
options = append(options, libp2p.Ping(false))
if features.Get().DisableResourceManager {
options = append(options, libp2p.ResourceManager(&network.NullResourceManager{}))
}
return options
}

View File

@@ -1183,7 +1183,7 @@ func TestServer_SubmitAttestations_InvalidAttestationGRPCHeader(t *testing.T) {
require.Equal(t, true, ok, "could not retrieve custom error metadata value")
assert.DeepEqual(
t,
[]string{"{\"failures\":[{\"index\":0,\"message\":\"Incorrect attestation signature: signature must be 96 bytes\"}]}"},
[]string{"{\"failures\":[{\"index\":0,\"message\":\"Incorrect attestation signature: could not create signature from byte slice: signature must be 96 bytes\"}]}"},
v,
)
}

View File

@@ -125,6 +125,14 @@ var (
Help: "Time to verify gossiped blocks",
},
)
// Sync committee verification performance.
syncMessagesForUnknownBlocks = promauto.NewCounter(
prometheus.CounterOpts{
Name: "sync_committee_messages_unknown_root",
Help: "The number of sync committee messages that are checked against DB to see if there vote is for an unknown root",
},
)
)
func (s *Service) updateMetrics() {

View File

@@ -90,7 +90,7 @@ func (s *Service) validateSyncCommitteeMessage(
ctx,
ignoreEmptyCommittee(committeeIndices),
s.rejectIncorrectSyncCommittee(committeeIndices, *msg.Topic),
s.ignoreHasSeenSyncMsg(m, committeeIndices),
s.ignoreHasSeenSyncMsg(ctx, m, committeeIndices),
s.rejectInvalidSyncCommitteeSignature(m),
); result != pubsub.ValidationAccept {
return result, err
@@ -123,24 +123,45 @@ func (s *Service) markSyncCommitteeMessagesSeen(committeeIndices []primitives.Co
subCommitteeSize := params.BeaconConfig().SyncCommitteeSize / params.BeaconConfig().SyncCommitteeSubnetCount
for _, idx := range committeeIndices {
subnet := uint64(idx) / subCommitteeSize
s.setSeenSyncMessageIndexSlot(m.Slot, m.ValidatorIndex, subnet)
s.setSeenSyncMessageIndexSlot(m, subnet)
}
}
// Returns true if the node has received sync committee for the validator with index and slot.
func (s *Service) hasSeenSyncMessageIndexSlot(slot primitives.Slot, valIndex primitives.ValidatorIndex, subCommitteeIndex uint64) bool {
func (s *Service) hasSeenSyncMessageIndexSlot(ctx context.Context, m *ethpb.SyncCommitteeMessage, subCommitteeIndex uint64) bool {
s.seenSyncMessageLock.RLock()
defer s.seenSyncMessageLock.RUnlock()
_, seen := s.seenSyncMessageCache.Get(seenSyncCommitteeKey(slot, valIndex, subCommitteeIndex))
return seen
rt, seen := s.seenSyncMessageCache.Get(seenSyncCommitteeKey(m.Slot, m.ValidatorIndex, subCommitteeIndex))
if !seen {
// return early if this is the first message
return false
}
root, ok := rt.([32]byte)
if !ok {
return true // Impossible. Return true to be safe
}
if !s.cfg.chain.InForkchoice(root) && !s.cfg.beaconDB.HasBlock(ctx, root) {
syncMessagesForUnknownBlocks.Inc()
return true
}
msgRoot := [32]byte(m.BlockRoot)
if !s.cfg.chain.InForkchoice(msgRoot) && !s.cfg.beaconDB.HasBlock(ctx, msgRoot) {
syncMessagesForUnknownBlocks.Inc()
return false
}
headRoot := s.cfg.chain.CachedHeadRoot()
if root == headRoot {
return true
}
return msgRoot != headRoot
}
// Set sync committee message validator index and slot as seen.
func (s *Service) setSeenSyncMessageIndexSlot(slot primitives.Slot, valIndex primitives.ValidatorIndex, subCommitteeIndex uint64) {
func (s *Service) setSeenSyncMessageIndexSlot(m *ethpb.SyncCommitteeMessage, subCommitteeIndex uint64) {
s.seenSyncMessageLock.Lock()
defer s.seenSyncMessageLock.Unlock()
key := seenSyncCommitteeKey(slot, valIndex, subCommitteeIndex)
s.seenSyncMessageCache.Add(key, true)
key := seenSyncCommitteeKey(m.Slot, m.ValidatorIndex, subCommitteeIndex)
s.seenSyncMessageCache.Add(key, [32]byte(m.BlockRoot))
}
// The `subnet_id` is valid for the given validator. This implies the validator is part of the broader
@@ -184,7 +205,7 @@ func (s *Service) rejectIncorrectSyncCommittee(
// There has been no other valid sync committee signature for the declared `slot`, `validator_index`,
// and `subcommittee_index`. In the event of `validator_index` belongs to multiple subnets, as long
// as one subnet has not been seen, we should let it in.
func (s *Service) ignoreHasSeenSyncMsg(
func (s *Service) ignoreHasSeenSyncMsg(ctx context.Context,
m *ethpb.SyncCommitteeMessage, committeeIndices []primitives.CommitteeIndex,
) validationFn {
return func(ctx context.Context) (pubsub.ValidationResult, error) {
@@ -192,7 +213,7 @@ func (s *Service) ignoreHasSeenSyncMsg(
subCommitteeSize := params.BeaconConfig().SyncCommitteeSize / params.BeaconConfig().SyncCommitteeSubnetCount
for _, idx := range committeeIndices {
subnet := uint64(idx) / subCommitteeSize
if !s.hasSeenSyncMessageIndexSlot(m.Slot, m.ValidatorIndex, subnet) {
if !s.hasSeenSyncMessageIndexSlot(ctx, m, subnet) {
isValid = true
break
}

View File

@@ -144,8 +144,12 @@ func TestService_ValidateSyncCommitteeMessage(t *testing.T) {
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
s.cfg.beaconDB = beaconDB
s.initCaches()
s.setSeenSyncMessageIndexSlot(1, 1, 0)
m := &ethpb.SyncCommitteeMessage{
Slot: 1,
ValidatorIndex: 1,
BlockRoot: params.BeaconConfig().ZeroHash[:],
}
s.setSeenSyncMessageIndexSlot(m, 0)
return s, topic, startup.NewClock(time.Now(), [32]byte{})
},
args: args{
@@ -441,10 +445,15 @@ func TestService_ignoreHasSeenSyncMsg(t *testing.T) {
name: "has seen",
setupSvc: func(s *Service, msg *ethpb.SyncCommitteeMessage, topic string) (*Service, string) {
s.initCaches()
s.setSeenSyncMessageIndexSlot(1, 0, 0)
m := &ethpb.SyncCommitteeMessage{
Slot: 1,
BlockRoot: params.BeaconConfig().ZeroHash[:],
}
s.setSeenSyncMessageIndexSlot(m, 0)
return s, ""
},
msg: &ethpb.SyncCommitteeMessage{ValidatorIndex: 0, Slot: 1},
msg: &ethpb.SyncCommitteeMessage{ValidatorIndex: 0, Slot: 1,
BlockRoot: params.BeaconConfig().ZeroHash[:]},
committee: []primitives.CommitteeIndex{1, 2, 3},
want: pubsub.ValidationIgnore,
},
@@ -452,19 +461,26 @@ func TestService_ignoreHasSeenSyncMsg(t *testing.T) {
name: "has not seen",
setupSvc: func(s *Service, msg *ethpb.SyncCommitteeMessage, topic string) (*Service, string) {
s.initCaches()
s.setSeenSyncMessageIndexSlot(1, 0, 0)
m := &ethpb.SyncCommitteeMessage{
Slot: 1,
BlockRoot: params.BeaconConfig().ZeroHash[:],
}
s.setSeenSyncMessageIndexSlot(m, 0)
return s, ""
},
msg: &ethpb.SyncCommitteeMessage{ValidatorIndex: 1, Slot: 1},
msg: &ethpb.SyncCommitteeMessage{ValidatorIndex: 1, Slot: 1,
BlockRoot: bytesutil.PadTo([]byte{'A'}, 32)},
committee: []primitives.CommitteeIndex{1, 2, 3},
want: pubsub.ValidationAccept,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Service{}
s := &Service{
cfg: &config{chain: &mockChain.ChainService{}},
}
s, _ = tt.setupSvc(s, tt.msg, "")
f := s.ignoreHasSeenSyncMsg(tt.msg, tt.committee)
f := s.ignoreHasSeenSyncMsg(context.Background(), tt.msg, tt.committee)
result, err := f(context.Background())
_ = err
require.Equal(t, tt.want, result)

View File

@@ -60,6 +60,7 @@ type Flags struct {
SaveFullExecutionPayloads bool // Save full beacon blocks with execution payloads in the database.
EnableStartOptimistic bool // EnableStartOptimistic treats every block as optimistic at startup.
DisableResourceManager bool // Disables running the node with libp2p's resource manager.
DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks
EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails
@@ -72,6 +73,9 @@ type Flags struct {
// KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have
// changed on disk. This feature is for advanced use cases only.
KeystoreImportDebounceInterval time.Duration
// AggregateIntervals specifies the time durations at which we aggregate attestations preparing for forkchoice.
AggregateIntervals [3]time.Duration
}
var featureConfig *Flags
@@ -214,10 +218,16 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
logEnabled(prepareAllPayloads)
cfg.PrepareAllPayloads = true
}
if ctx.IsSet(buildBlockParallel.Name) {
logEnabled(buildBlockParallel)
cfg.BuildBlockParallel = true
cfg.BuildBlockParallel = true
if ctx.IsSet(disableBuildBlockParallel.Name) {
logEnabled(disableBuildBlockParallel)
cfg.BuildBlockParallel = false
}
if ctx.IsSet(disableResourceManager.Name) {
logEnabled(disableResourceManager)
cfg.DisableResourceManager = true
}
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
Init(cfg)
return nil
}

View File

@@ -32,6 +32,11 @@ var (
Usage: deprecatedUsage,
Hidden: true,
}
deprecatedBuildBlockParallel = &cli.BoolFlag{
Name: "build-block-parallel",
Usage: deprecatedUsage,
Hidden: true,
}
)
// Deprecated flags for both the beacon node and validator client.
@@ -41,6 +46,7 @@ var deprecatedFlags = []cli.Flag{
deprecatedDisableVecHTR,
deprecatedEnableReorgLateBlocks,
deprecatedDisableGossipBatchAggregation,
deprecatedBuildBlockParallel,
}
// deprecatedBeaconFlags contains flags that are still used by other components

View File

@@ -50,6 +50,24 @@ var (
Usage: "(Danger): Writes the wallet password to the wallet directory on completing Prysm web onboarding. " +
"We recommend against this flag unless you are an advanced user.",
}
aggregateFirstInterval = &cli.DurationFlag{
Name: "aggregate-first-interval",
Usage: "(Advanced): Specifies the first interval in which attestations are aggregated in the slot (typically unnaggregated attestations are aggregated in this interval)",
Value: 6500 * time.Millisecond,
Hidden: true,
}
aggregateSecondInterval = &cli.DurationFlag{
Name: "aggregate-second-interval",
Usage: "(Advanced): Specifies the second interval in which attestations are aggregated in the slot",
Value: 9500 * time.Millisecond,
Hidden: true,
}
aggregateThirdInterval = &cli.DurationFlag{
Name: "aggregate-third-interval",
Usage: "(Advanced): Specifies the third interval in which attestations are aggregated in the slot",
Value: 11800 * time.Millisecond,
Hidden: true,
}
dynamicKeyReloadDebounceInterval = &cli.DurationFlag{
Name: "dynamic-key-reload-debounce-interval",
Usage: "(Advanced): Specifies the time duration the validator waits to reload new keys if they have " +
@@ -118,9 +136,13 @@ var (
Name: "prepare-all-payloads",
Usage: "Informs the engine to prepare all local payloads. Useful for relayers and builders",
}
buildBlockParallel = &cli.BoolFlag{
Name: "build-block-parallel",
Usage: "Builds a beacon block in parallel for consensus and execution. It results in faster block construction time",
disableBuildBlockParallel = &cli.BoolFlag{
Name: "disable-build-block-parallel",
Usage: "Disables building a beacon block in parallel for consensus and execution",
}
disableResourceManager = &cli.BoolFlag{
Name: "disable-resource-manager",
Usage: "Disables running the libp2p resource manager",
}
)
@@ -168,7 +190,11 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
enableVerboseSigVerification,
enableOptionalEngineMethods,
prepareAllPayloads,
buildBlockParallel,
disableBuildBlockParallel,
aggregateFirstInterval,
aggregateSecondInterval,
aggregateThirdInterval,
disableResourceManager,
}...)...)
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.

View File

@@ -1,12 +1,32 @@
load("@prysm//tools/go:def.bzl", "go_library")
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["proposer-settings.go"],
srcs = ["proposer_settings.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/config/validator/service",
visibility = ["//visibility:public"],
deps = [
"//config/fieldparams:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["proposer_settings_test.go"],
embed = [":go_default_library"],
deps = [
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
],
)

View File

@@ -1,79 +0,0 @@
package validator_service_config
import (
"strconv"
"github.com/ethereum/go-ethereum/common"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
)
// ProposerSettingsPayload is the struct representation of the JSON or YAML payload set in the validator through the CLI.
// ProposerConfig is the map of validator address to fee recipient options all in hex format.
// DefaultConfig is the default fee recipient address for all validators unless otherwise specified in the propose config.required.
type ProposerSettingsPayload struct {
ProposerConfig map[string]*ProposerOptionPayload `json:"proposer_config" yaml:"proposer_config"`
DefaultConfig *ProposerOptionPayload `json:"default_config" yaml:"default_config"`
}
// ProposerOptionPayload is the struct representation of the JSON config file set in the validator through the CLI.
// FeeRecipient is set to an eth address in hex string format with 0x prefix.
type ProposerOptionPayload struct {
FeeRecipient string `json:"fee_recipient" yaml:"fee_recipient"`
BuilderConfig *BuilderConfig `json:"builder" yaml:"builder"`
}
// BuilderConfig is the struct representation of the JSON config file set in the validator through the CLI.
// GasLimit is a number set to help the network decide on the maximum gas in each block.
type BuilderConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
GasLimit Uint64 `json:"gas_limit,omitempty" yaml:"gas_limit,omitempty"`
Relays []string `json:"relays" yaml:"relays"`
}
type Uint64 uint64
func (u *Uint64) UnmarshalJSON(bs []byte) error {
str := string(bs) // Parse plain numbers directly.
if bs[0] == '"' && bs[len(bs)-1] == '"' {
// Unwrap the quotes from string numbers.
str = string(bs[1 : len(bs)-1])
}
x, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return err
}
*u = Uint64(x)
return nil
}
func (u *Uint64) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
err := unmarshal(&str)
if err != nil {
return err
}
x, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return err
}
*u = Uint64(x)
return nil
}
// ProposerSettings is a Prysm internal representation of the fee recipient config on the validator client.
// ProposerSettingsPayload maps to ProposerSettings on import through the CLI.
type ProposerSettings struct {
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption
DefaultConfig *ProposerOption
}
type FeeRecipientConfig struct {
FeeRecipient common.Address
}
// ProposerOption is a Prysm internal representation of the ProposerOptionPayload on the validator client in bytes format instead of hex.
type ProposerOption struct {
FeeRecipientConfig *FeeRecipientConfig
BuilderConfig *BuilderConfig
}

View File

@@ -0,0 +1,206 @@
package validator_service_config
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
)
// ToSettings converts struct to ProposerSettings
func ToSettings(ps *validatorpb.ProposerSettingsPayload) (*ProposerSettings, error) {
settings := &ProposerSettings{}
if ps.ProposerConfig != nil {
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption)
for key, optionPayload := range ps.ProposerConfig {
if optionPayload.FeeRecipient == "" {
continue
}
b, err := hexutil.Decode(key)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("cannot decode public key %s", key))
}
p := &ProposerOption{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress(optionPayload.FeeRecipient),
},
}
if optionPayload.Builder != nil {
p.BuilderConfig = ToBuilderConfig(optionPayload.Builder)
}
settings.ProposeConfig[bytesutil.ToBytes48(b)] = p
}
}
if ps.DefaultConfig != nil {
d := &ProposerOption{}
if ps.DefaultConfig.FeeRecipient != "" {
d.FeeRecipientConfig = &FeeRecipientConfig{
FeeRecipient: common.HexToAddress(ps.DefaultConfig.FeeRecipient),
}
}
if ps.DefaultConfig.Builder != nil {
d.BuilderConfig = ToBuilderConfig(ps.DefaultConfig.Builder)
}
settings.DefaultConfig = d
}
return settings, nil
}
// BuilderConfig is the struct representation of the JSON config file set in the validator through the CLI.
// GasLimit is a number set to help the network decide on the maximum gas in each block.
type BuilderConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
GasLimit validator.Uint64 `json:"gas_limit,omitempty" yaml:"gas_limit,omitempty"`
Relays []string `json:"relays,omitempty" yaml:"relays,omitempty"`
}
// ToBuilderConfig converts protobuf to a builder config used in inmemory storage
func ToBuilderConfig(from *validatorpb.BuilderConfig) *BuilderConfig {
if from == nil {
return nil
}
config := &BuilderConfig{
Enabled: from.Enabled,
GasLimit: from.GasLimit,
}
if from.Relays != nil {
relays := make([]string, len(from.Relays))
copy(relays, from.Relays)
config.Relays = relays
}
return config
}
// ProposerSettings is a Prysm internal representation of the fee recipient config on the validator client.
// validatorpb.ProposerSettingsPayload maps to ProposerSettings on import through the CLI.
type ProposerSettings struct {
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption
DefaultConfig *ProposerOption
}
// ToPayload converts struct to ProposerSettingsPayload
func (ps *ProposerSettings) ToPayload() *validatorpb.ProposerSettingsPayload {
if ps == nil {
return nil
}
payload := &validatorpb.ProposerSettingsPayload{}
if ps.ProposeConfig != nil {
payload.ProposerConfig = make(map[string]*validatorpb.ProposerOptionPayload)
for key, option := range ps.ProposeConfig {
p := &validatorpb.ProposerOptionPayload{}
if option.FeeRecipientConfig != nil {
p.FeeRecipient = option.FeeRecipientConfig.FeeRecipient.Hex()
}
if option.BuilderConfig != nil {
p.Builder = option.BuilderConfig.ToPayload()
}
payload.ProposerConfig[hexutil.Encode(key[:])] = p
}
}
if ps.DefaultConfig != nil {
p := &validatorpb.ProposerOptionPayload{}
if ps.DefaultConfig.FeeRecipientConfig != nil {
p.FeeRecipient = ps.DefaultConfig.FeeRecipientConfig.FeeRecipient.Hex()
}
if ps.DefaultConfig.BuilderConfig != nil {
p.Builder = ps.DefaultConfig.BuilderConfig.ToPayload()
}
payload.DefaultConfig = p
}
return payload
}
// FeeRecipientConfig is a prysm internal representation to see if the fee recipient was set.
type FeeRecipientConfig struct {
FeeRecipient common.Address
}
// ProposerOption is a Prysm internal representation of the ProposerOptionPayload on the validator client in bytes format instead of hex.
type ProposerOption struct {
FeeRecipientConfig *FeeRecipientConfig
BuilderConfig *BuilderConfig
}
// Clone creates a deep copy of the proposer settings
func (ps *ProposerSettings) Clone() *ProposerSettings {
if ps == nil {
return nil
}
clone := &ProposerSettings{}
if ps.DefaultConfig != nil {
clone.DefaultConfig = ps.DefaultConfig.Clone()
}
if ps.ProposeConfig != nil {
clone.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption)
for k, v := range ps.ProposeConfig {
keyCopy := k
valCopy := v.Clone()
clone.ProposeConfig[keyCopy] = valCopy
}
}
return clone
}
// Clone creates a deep copy of fee recipient config
func (fo *FeeRecipientConfig) Clone() *FeeRecipientConfig {
if fo == nil {
return nil
}
return &FeeRecipientConfig{fo.FeeRecipient}
}
// Clone creates a deep copy of builder config
func (bc *BuilderConfig) Clone() *BuilderConfig {
if bc == nil {
return nil
}
config := &BuilderConfig{}
config.Enabled = bc.Enabled
config.GasLimit = bc.GasLimit
var relays []string
if bc.Relays != nil {
relays = make([]string, len(bc.Relays))
copy(relays, bc.Relays)
config.Relays = relays
}
return config
}
// ToPayload converts Builder Config to the protobuf object
func (bc *BuilderConfig) ToPayload() *validatorpb.BuilderConfig {
if bc == nil {
return nil
}
config := &validatorpb.BuilderConfig{}
config.Enabled = bc.Enabled
var relays []string
if bc.Relays != nil {
relays = make([]string, len(bc.Relays))
copy(relays, bc.Relays)
config.Relays = relays
}
config.GasLimit = bc.GasLimit
return config
}
// Clone creates a deep copy of proposer option
func (po *ProposerOption) Clone() *ProposerOption {
if po == nil {
return nil
}
p := &ProposerOption{}
if po.FeeRecipientConfig != nil {
p.FeeRecipientConfig = po.FeeRecipientConfig.Clone()
}
if po.BuilderConfig != nil {
p.BuilderConfig = po.BuilderConfig.Clone()
}
return p
}

View File

@@ -0,0 +1,100 @@
package validator_service_config
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func Test_Proposer_Setting_Cloning(t *testing.T) {
key1hex := "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a"
key1, err := hexutil.Decode(key1hex)
require.NoError(t, err)
settings := &ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
Relays: []string{"https://example-relay.com"},
},
},
},
DefaultConfig: &ProposerOption{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
Relays: []string{"https://example-relay.com"},
},
},
}
t.Run("Happy Path Cloning", func(t *testing.T) {
clone := settings.Clone()
require.DeepEqual(t, settings, clone)
option, ok := settings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, ok)
newFeeRecipient := "0x44455530FCE8a85ec7055A5F8b2bE214B3DaeFd3"
option.FeeRecipientConfig.FeeRecipient = common.HexToAddress(newFeeRecipient)
coption, k := clone.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, k)
require.NotEqual(t, option.FeeRecipientConfig.FeeRecipient.Hex(), coption.FeeRecipientConfig.FeeRecipient.Hex())
require.Equal(t, "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3", coption.FeeRecipientConfig.FeeRecipient.Hex())
})
t.Run("Happy Path Cloning Builder config", func(t *testing.T) {
clone := settings.DefaultConfig.BuilderConfig.Clone()
require.DeepEqual(t, settings.DefaultConfig.BuilderConfig, clone)
settings.DefaultConfig.BuilderConfig.GasLimit = 1
require.NotEqual(t, settings.DefaultConfig.BuilderConfig.GasLimit, clone.GasLimit)
})
t.Run("Happy Path ToBuilderConfig", func(t *testing.T) {
clone := settings.DefaultConfig.BuilderConfig.Clone()
config := ToBuilderConfig(clone.ToPayload())
require.DeepEqual(t, config.Relays, clone.Relays)
require.Equal(t, config.Enabled, clone.Enabled)
require.Equal(t, config.GasLimit, clone.GasLimit)
})
t.Run("To Payload and ToSettings", func(t *testing.T) {
payload := settings.ToPayload()
option, ok := settings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, ok)
fee := option.FeeRecipientConfig.FeeRecipient.Hex()
potion, pok := payload.ProposerConfig[key1hex]
require.Equal(t, true, pok)
require.Equal(t, option.FeeRecipientConfig.FeeRecipient.Hex(), potion.FeeRecipient)
require.Equal(t, settings.DefaultConfig.FeeRecipientConfig.FeeRecipient.Hex(), payload.DefaultConfig.FeeRecipient)
require.Equal(t, settings.DefaultConfig.BuilderConfig.Enabled, payload.DefaultConfig.Builder.Enabled)
potion.FeeRecipient = ""
newSettings, err := ToSettings(payload)
require.NoError(t, err)
// when converting to settings if a fee recipient is empty string then it will be skipped
noption, ok := newSettings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, false, ok)
require.Equal(t, true, noption == nil)
require.DeepEqual(t, newSettings.DefaultConfig, settings.DefaultConfig)
// if fee recipient is set it will not skip
potion.FeeRecipient = fee
newSettings, err = ToSettings(payload)
require.NoError(t, err)
noption, ok = newSettings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, ok)
require.Equal(t, option.FeeRecipientConfig.FeeRecipient.Hex(), noption.FeeRecipientConfig.FeeRecipient.Hex())
require.Equal(t, option.BuilderConfig.GasLimit, option.BuilderConfig.GasLimit)
require.Equal(t, option.BuilderConfig.Enabled, option.BuilderConfig.Enabled)
})
}

View File

@@ -0,0 +1,18 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["custom_types.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/consensus-types/validator",
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["custom_types_test.go"],
embed = [":go_default_library"],
deps = [
"//testing/require:go_default_library",
"@io_k8s_apimachinery//pkg/util/yaml:go_default_library",
],
)

View File

@@ -0,0 +1,41 @@
package validator
import "strconv"
// Uint64 custom uint64 to be unmarshallable
type Uint64 uint64
// UnmarshalJSON custom unmarshal function for json
func (u *Uint64) UnmarshalJSON(bs []byte) error {
str := string(bs) // Parse plain numbers directly.
if str == "" {
*u = Uint64(0)
return nil
}
if len(bs) >= 3 && bs[0] == '"' && bs[len(bs)-1] == '"' {
// Unwrap the quotes from string numbers.
str = string(bs[1 : len(bs)-1])
}
x, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return err
}
*u = Uint64(x)
return nil
}
// UnmarshalYAML custom unmarshal function for yaml
func (u *Uint64) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
err := unmarshal(&str)
if err != nil {
return err
}
x, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return err
}
*u = Uint64(x)
return nil
}

View File

@@ -0,0 +1,58 @@
package validator
import (
"testing"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"k8s.io/apimachinery/pkg/util/yaml"
)
func Test_customUint_UnmarshalJSON(t *testing.T) {
type Custom struct {
Test Uint64 `json:"test"`
}
tests := []struct {
name string
jsonString string
number uint64
wantUnmarshalErr string
}{
{
name: "Happy Path string",
jsonString: `{"test": "123441"}`,
number: 123441,
},
{
name: "Happy Path number",
jsonString: `{"test": 123441}`,
number: 123441,
},
{
name: "empty",
jsonString: `{"test":""}`,
wantUnmarshalErr: "error unmarshaling JSON",
},
{
name: "digits more than uint64",
jsonString: `{"test":"8888888888888888888888888888888888888888888888888888888888888"}`,
wantUnmarshalErr: "error unmarshaling JSON",
},
{
name: "not a uint64",
jsonString: `{"test":"one hundred"}`,
wantUnmarshalErr: "error unmarshaling JSON",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var to Custom
err := yaml.Unmarshal([]byte(tt.jsonString), &to)
if tt.wantUnmarshalErr != "" {
require.ErrorContains(t, tt.wantUnmarshalErr, err)
} else {
require.NoError(t, err)
}
require.Equal(t, tt.number, uint64(to.Test))
})
}
}

View File

@@ -24,6 +24,13 @@ func PublicKeyFromBytes(pubKey []byte) (PublicKey, error) {
return blst.PublicKeyFromBytes(pubKey)
}
// SignatureFromBytesNoValidation creates a BLS signature from a LittleEndian byte slice.
// It does not check validity of the signature, use only when the byte slice has
// already been verified
func SignatureFromBytesNoValidation(sig []byte) (Signature, error) {
return blst.SignatureFromBytesNoValidation(sig)
}
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
func SignatureFromBytes(sig []byte) (Signature, error) {
return blst.SignatureFromBytes(sig)

View File

@@ -24,8 +24,9 @@ type Signature struct {
s *blstSignature
}
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
func SignatureFromBytes(sig []byte) (common.Signature, error) {
// signatureFromBytesNoValidation creates a BLS signature from a LittleEndian
// byte slice. It does not validate that the signature is in the BLS group
func signatureFromBytesNoValidation(sig []byte) (*blstSignature, error) {
if len(sig) != fieldparams.BLSSignatureLength {
return nil, fmt.Errorf("signature must be %d bytes", fieldparams.BLSSignatureLength)
}
@@ -33,6 +34,25 @@ func SignatureFromBytes(sig []byte) (common.Signature, error) {
if signature == nil {
return nil, errors.New("could not unmarshal bytes into signature")
}
return signature, nil
}
// SignatureFromBytesNoValidation creates a BLS signature from a LittleEndian
// byte slice. It does not validate that the signature is in the BLS group
func SignatureFromBytesNoValidation(sig []byte) (common.Signature, error) {
signature, err := signatureFromBytesNoValidation(sig)
if err != nil {
return nil, errors.Wrap(err, "could not create signature from byte slice")
}
return &Signature{s: signature}, nil
}
// SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
func SignatureFromBytes(sig []byte) (common.Signature, error) {
signature, err := signatureFromBytesNoValidation(sig)
if err != nil {
return nil, errors.Wrap(err, "could not create signature from byte slice")
}
// Group check signature. Do not check for infinity since an aggregated signature
// could be infinite.
if !signature.SigValidate(false) {

View File

@@ -207,6 +207,11 @@ func TestSignatureFromBytes(t *testing.T) {
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
err: errors.New("could not unmarshal bytes into signature"),
},
{
input: []byte{0xac, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84},
name: "Not in group",
err: errors.New("signature not in group"),
},
{
name: "Good",
input: []byte{0xab, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84},
@@ -227,6 +232,60 @@ func TestSignatureFromBytes(t *testing.T) {
}
}
func TestSignatureFromBytesNoValidation(t *testing.T) {
tests := []struct {
name string
input []byte
err error
}{
{
name: "Nil",
err: errors.New("signature must be 96 bytes"),
},
{
name: "Empty",
input: []byte{},
err: errors.New("signature must be 96 bytes"),
},
{
name: "Short",
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
err: errors.New("signature must be 96 bytes"),
},
{
name: "Long",
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
err: errors.New("signature must be 96 bytes"),
},
{
name: "Bad",
input: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
err: errors.New("could not unmarshal bytes into signature"),
},
{
name: "Not in group",
input: []byte{0xac, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84},
},
{
name: "Good",
input: []byte{0xab, 0xb0, 0x12, 0x4c, 0x75, 0x74, 0xf2, 0x81, 0xa2, 0x93, 0xf4, 0x18, 0x5c, 0xad, 0x3c, 0xb2, 0x26, 0x81, 0xd5, 0x20, 0x91, 0x7c, 0xe4, 0x66, 0x65, 0x24, 0x3e, 0xac, 0xb0, 0x51, 0x00, 0x0d, 0x8b, 0xac, 0xf7, 0x5e, 0x14, 0x51, 0x87, 0x0c, 0xa6, 0xb3, 0xb9, 0xe6, 0xc9, 0xd4, 0x1a, 0x7b, 0x02, 0xea, 0xd2, 0x68, 0x5a, 0x84, 0x18, 0x8a, 0x4f, 0xaf, 0xd3, 0x82, 0x5d, 0xaf, 0x6a, 0x98, 0x96, 0x25, 0xd7, 0x19, 0xcc, 0xd2, 0xd8, 0x3a, 0x40, 0x10, 0x1f, 0x4a, 0x45, 0x3f, 0xca, 0x62, 0x87, 0x8c, 0x89, 0x0e, 0xca, 0x62, 0x23, 0x63, 0xf9, 0xdd, 0xb8, 0xf3, 0x67, 0xa9, 0x1e, 0x84},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := SignatureFromBytesNoValidation(test.input)
if test.err != nil {
assert.NotEqual(t, nil, err, "No error returned")
assert.ErrorContains(t, test.err.Error(), err, "Unexpected error returned")
} else {
assert.NoError(t, err)
assert.DeepEqual(t, 0, bytes.Compare(res.Marshal(), test.input))
}
})
}
}
func TestMultipleSignatureFromBytes(t *testing.T) {
tests := []struct {
name string

View File

@@ -84,7 +84,7 @@ func TestVerifyVerbosely_VerificationThrowsError(t *testing.T) {
valid, err := set.VerifyVerbosely()
assert.Equal(t, false, valid, "SignatureSet is expected to be invalid")
assert.StringContains(t, "signature 'signature of bad0' is invalid", err.Error())
assert.StringContains(t, "error: could not unmarshal bytes into signature", err.Error())
assert.StringContains(t, "could not unmarshal bytes into signature", err.Error())
assert.StringNotContains(t, "signature 'signature of good0' is invalid", err.Error())
}

2
go.mod
View File

@@ -91,6 +91,7 @@ require (
gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.20.0
k8s.io/client-go v0.20.0
)
@@ -233,7 +234,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
k8s.io/apimachinery v0.20.0 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
nhooyr.io/websocket v1.8.7 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.0.2 // indirect

View File

@@ -18,3 +18,7 @@ latest_version_tag=$(./hack/latest_version_tag.sh)
echo "STABLE_VERSION_TAG $latest_version_tag"
echo "STABLE_COMMIT_SHA $commit_sha"
echo "STABLE_GIT_TAG $latest_version_tag"
echo DOCKER_TAG "$(git rev-parse --abbrev-ref HEAD)-$(git rev-parse --short=6 HEAD)"
echo DATE "$(date --rfc-3339=seconds --utc)"
echo DATE_UNIX "$(date --utc +%s)"

View File

@@ -15,7 +15,7 @@ type attList []*ethpb.Attestation
// significantly more expensive than the inner logic of AggregateAttestations so they must be
// substituted for benchmarks which analyze AggregateAttestations.
var aggregateSignatures = bls.AggregateSignatures
var signatureFromBytes = bls.SignatureFromBytes
var signatureFromBytes = bls.SignatureFromBytesNoValidation
var _ = logrus.WithField("prefix", "aggregation.attestations")
@@ -36,6 +36,43 @@ func Aggregate(atts []*ethpb.Attestation) ([]*ethpb.Attestation, error) {
return MaxCoverAttestationAggregation(atts)
}
// AggregateDisjointOneBitAtts aggregates unaggregated attestations with the
// exact same attestation data.
func AggregateDisjointOneBitAtts(atts []*ethpb.Attestation) (*ethpb.Attestation, error) {
if len(atts) == 0 {
return nil, nil
}
if len(atts) == 1 {
return atts[0], nil
}
coverage, err := atts[0].AggregationBits.ToBitlist64()
if err != nil {
return nil, errors.Wrap(err, "could not get aggregation bits")
}
for _, att := range atts[1:] {
bits, err := att.AggregationBits.ToBitlist64()
if err != nil {
return nil, errors.Wrap(err, "could not get aggregation bits")
}
err = coverage.NoAllocOr(bits, coverage)
if err != nil {
return nil, errors.Wrap(err, "could not get aggregation bits")
}
}
keys := make([]int, len(atts))
for i := 0; i < len(atts); i++ {
keys[i] = i
}
idx, err := aggregateAttestations(atts, keys, coverage)
if err != nil {
return nil, errors.Wrap(err, "could not aggregate attestations")
}
if idx != 0 {
return nil, errors.New("could not aggregate attestations, obtained non zero index")
}
return atts[0], nil
}
// AggregatePair aggregates pair of attestations a1 and a2 together.
func AggregatePair(a1, a2 *ethpb.Attestation) (*ethpb.Attestation, error) {
o, err := a1.AggregationBits.Overlaps(a2.AggregationBits)

View File

@@ -54,6 +54,7 @@ go_proto_library(
"@com_github_grpc_ecosystem_grpc_gateway_v2//protoc-gen-openapiv2/options:options_go_proto",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"@go_googleapis//google/api:annotations_go_proto",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//runtime/protoimpl:go_default_library",

View File

@@ -13,6 +13,7 @@ import (
empty "github.com/golang/protobuf/ptypes/empty"
github_com_prysmaticlabs_prysm_v4_consensus_types_primitives "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
github_com_prysmaticlabs_prysm_v4_consensus_types_validator "github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
_ "github.com/prysmaticlabs/prysm/v4/proto/eth/ext"
v1alpha1 "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
_ "google.golang.org/genproto/googleapis/api/annotations"
@@ -479,6 +480,179 @@ func (x *SignResponse) GetStatus() SignResponse_Status {
return SignResponse_UNKNOWN
}
type ProposerOptionPayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FeeRecipient string `protobuf:"bytes,1,opt,name=fee_recipient,json=feeRecipient,proto3" json:"fee_recipient,omitempty"`
Builder *BuilderConfig `protobuf:"bytes,2,opt,name=builder,proto3" json:"builder,omitempty"`
}
func (x *ProposerOptionPayload) Reset() {
*x = ProposerOptionPayload{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProposerOptionPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProposerOptionPayload) ProtoMessage() {}
func (x *ProposerOptionPayload) ProtoReflect() protoreflect.Message {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProposerOptionPayload.ProtoReflect.Descriptor instead.
func (*ProposerOptionPayload) Descriptor() ([]byte, []int) {
return file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDescGZIP(), []int{3}
}
func (x *ProposerOptionPayload) GetFeeRecipient() string {
if x != nil {
return x.FeeRecipient
}
return ""
}
func (x *ProposerOptionPayload) GetBuilder() *BuilderConfig {
if x != nil {
return x.Builder
}
return nil
}
type BuilderConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
GasLimit github_com_prysmaticlabs_prysm_v4_consensus_types_validator.Uint64 `protobuf:"varint,2,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v4/consensus-types/validator.Uint64"`
Relays []string `protobuf:"bytes,3,rep,name=relays,proto3" json:"relays,omitempty"`
}
func (x *BuilderConfig) Reset() {
*x = BuilderConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BuilderConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BuilderConfig) ProtoMessage() {}
func (x *BuilderConfig) ProtoReflect() protoreflect.Message {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BuilderConfig.ProtoReflect.Descriptor instead.
func (*BuilderConfig) Descriptor() ([]byte, []int) {
return file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDescGZIP(), []int{4}
}
func (x *BuilderConfig) GetEnabled() bool {
if x != nil {
return x.Enabled
}
return false
}
func (x *BuilderConfig) GetGasLimit() github_com_prysmaticlabs_prysm_v4_consensus_types_validator.Uint64 {
if x != nil {
return x.GasLimit
}
return github_com_prysmaticlabs_prysm_v4_consensus_types_validator.Uint64(0)
}
func (x *BuilderConfig) GetRelays() []string {
if x != nil {
return x.Relays
}
return nil
}
type ProposerSettingsPayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ProposerConfig map[string]*ProposerOptionPayload `protobuf:"bytes,1,rep,name=proposer_config,json=proposerConfig,proto3" json:"proposer_config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
DefaultConfig *ProposerOptionPayload `protobuf:"bytes,2,opt,name=default_config,json=defaultConfig,proto3" json:"default_config,omitempty"`
}
func (x *ProposerSettingsPayload) Reset() {
*x = ProposerSettingsPayload{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProposerSettingsPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProposerSettingsPayload) ProtoMessage() {}
func (x *ProposerSettingsPayload) ProtoReflect() protoreflect.Message {
mi := &file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProposerSettingsPayload.ProtoReflect.Descriptor instead.
func (*ProposerSettingsPayload) Descriptor() ([]byte, []int) {
return file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDescGZIP(), []int{5}
}
func (x *ProposerSettingsPayload) GetProposerConfig() map[string]*ProposerOptionPayload {
if x != nil {
return x.ProposerConfig
}
return nil
}
func (x *ProposerSettingsPayload) GetDefaultConfig() *ProposerOptionPayload {
if x != nil {
return x.DefaultConfig
}
return nil
}
var File_proto_prysm_v1alpha1_validator_client_keymanager_proto protoreflect.FileDescriptor
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDesc = []byte{
@@ -620,39 +794,80 @@ var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDesc = []byte
0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53,
0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45,
0x4e, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44,
0x10, 0x03, 0x32, 0xa7, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x69, 0x67,
0x6e, 0x65, 0x72, 0x12, 0x90, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69,
0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73,
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x36, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x75,
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x83, 0x01, 0x0a, 0x04, 0x53, 0x69, 0x67, 0x6e, 0x12,
0x2b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64,
0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32,
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x65,
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69,
0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x1a, 0x22, 0x18, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x32,
0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x42, 0xce, 0x01, 0x0a,
0x22, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61,
0x10, 0x03, 0x22, 0x85, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x4f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x23, 0x0a, 0x0d,
0x66, 0x65, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e,
0x74, 0x12, 0x47, 0x0a, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61,
0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73,
0x2e, 0x76, 0x32, 0x42, 0x0f, 0x4b, 0x65, 0x79, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73,
0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3b,
0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x70, 0x62, 0xaa, 0x02, 0x1e, 0x45, 0x74,
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72,
0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x1e, 0x45,
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
0x72, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x56, 0x32, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x22, 0xa6, 0x01, 0x0a, 0x0d, 0x42,
0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07,
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65,
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69,
0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x46, 0x82, 0xb5, 0x18, 0x42, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61,
0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x34,
0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73,
0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x36,
0x34, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x72,
0x65, 0x6c, 0x61, 0x79, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x6c,
0x61, 0x79, 0x73, 0x22, 0xe7, 0x02, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12,
0x74, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73,
0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
0x64, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5c, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e,
0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x50,
0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x1a, 0x78, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4b, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x65, 0x74,
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72,
0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f,
0x70, 0x6f, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xa7, 0x02,
0x0a, 0x0c, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x90,
0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6e,
0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x1a, 0x36, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76,
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76,
0x32, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x73, 0x12, 0x83, 0x01, 0x0a, 0x04, 0x53, 0x69, 0x67, 0x6e, 0x12, 0x2b, 0x2e, 0x65, 0x74, 0x68,
0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x18, 0x2f,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, 0x6d, 0x6f,
0x74, 0x65, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x42, 0xce, 0x01, 0x0a, 0x22, 0x6f, 0x72, 0x67, 0x2e,
0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
0x6f, 0x72, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x32, 0x42, 0x0f,
0x4b, 0x65, 0x79, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
0x01, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72,
0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73,
0x6d, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
0x74, 0x6f, 0x72, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3b, 0x76, 0x61, 0x6c, 0x69, 0x64,
0x61, 0x74, 0x6f, 0x72, 0x70, 0x62, 0xaa, 0x02, 0x1e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75,
0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x41, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x73, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x1e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65,
0x75, 0x6d, 0x5c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5c, 0x41, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -668,49 +883,57 @@ func file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDescGZIP() [
}
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_goTypes = []interface{}{
(SignResponse_Status)(0), // 0: ethereum.validator.accounts.v2.SignResponse.Status
(*ListPublicKeysResponse)(nil), // 1: ethereum.validator.accounts.v2.ListPublicKeysResponse
(*SignRequest)(nil), // 2: ethereum.validator.accounts.v2.SignRequest
(*SignResponse)(nil), // 3: ethereum.validator.accounts.v2.SignResponse
(*v1alpha1.BeaconBlock)(nil), // 4: ethereum.eth.v1alpha1.BeaconBlock
(*v1alpha1.AttestationData)(nil), // 5: ethereum.eth.v1alpha1.AttestationData
(*v1alpha1.AggregateAttestationAndProof)(nil), // 6: ethereum.eth.v1alpha1.AggregateAttestationAndProof
(*v1alpha1.VoluntaryExit)(nil), // 7: ethereum.eth.v1alpha1.VoluntaryExit
(*v1alpha1.BeaconBlockAltair)(nil), // 8: ethereum.eth.v1alpha1.BeaconBlockAltair
(*v1alpha1.SyncAggregatorSelectionData)(nil), // 9: ethereum.eth.v1alpha1.SyncAggregatorSelectionData
(*v1alpha1.ContributionAndProof)(nil), // 10: ethereum.eth.v1alpha1.ContributionAndProof
(*v1alpha1.BeaconBlockBellatrix)(nil), // 11: ethereum.eth.v1alpha1.BeaconBlockBellatrix
(*v1alpha1.BlindedBeaconBlockBellatrix)(nil), // 12: ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix
(*v1alpha1.ValidatorRegistrationV1)(nil), // 13: ethereum.eth.v1alpha1.ValidatorRegistrationV1
(*v1alpha1.BeaconBlockCapella)(nil), // 14: ethereum.eth.v1alpha1.BeaconBlockCapella
(*v1alpha1.BlindedBeaconBlockCapella)(nil), // 15: ethereum.eth.v1alpha1.BlindedBeaconBlockCapella
(*empty.Empty)(nil), // 16: google.protobuf.Empty
(*ProposerOptionPayload)(nil), // 4: ethereum.validator.accounts.v2.ProposerOptionPayload
(*BuilderConfig)(nil), // 5: ethereum.validator.accounts.v2.BuilderConfig
(*ProposerSettingsPayload)(nil), // 6: ethereum.validator.accounts.v2.ProposerSettingsPayload
nil, // 7: ethereum.validator.accounts.v2.ProposerSettingsPayload.ProposerConfigEntry
(*v1alpha1.BeaconBlock)(nil), // 8: ethereum.eth.v1alpha1.BeaconBlock
(*v1alpha1.AttestationData)(nil), // 9: ethereum.eth.v1alpha1.AttestationData
(*v1alpha1.AggregateAttestationAndProof)(nil), // 10: ethereum.eth.v1alpha1.AggregateAttestationAndProof
(*v1alpha1.VoluntaryExit)(nil), // 11: ethereum.eth.v1alpha1.VoluntaryExit
(*v1alpha1.BeaconBlockAltair)(nil), // 12: ethereum.eth.v1alpha1.BeaconBlockAltair
(*v1alpha1.SyncAggregatorSelectionData)(nil), // 13: ethereum.eth.v1alpha1.SyncAggregatorSelectionData
(*v1alpha1.ContributionAndProof)(nil), // 14: ethereum.eth.v1alpha1.ContributionAndProof
(*v1alpha1.BeaconBlockBellatrix)(nil), // 15: ethereum.eth.v1alpha1.BeaconBlockBellatrix
(*v1alpha1.BlindedBeaconBlockBellatrix)(nil), // 16: ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix
(*v1alpha1.ValidatorRegistrationV1)(nil), // 17: ethereum.eth.v1alpha1.ValidatorRegistrationV1
(*v1alpha1.BeaconBlockCapella)(nil), // 18: ethereum.eth.v1alpha1.BeaconBlockCapella
(*v1alpha1.BlindedBeaconBlockCapella)(nil), // 19: ethereum.eth.v1alpha1.BlindedBeaconBlockCapella
(*empty.Empty)(nil), // 20: google.protobuf.Empty
}
var file_proto_prysm_v1alpha1_validator_client_keymanager_proto_depIdxs = []int32{
4, // 0: ethereum.validator.accounts.v2.SignRequest.block:type_name -> ethereum.eth.v1alpha1.BeaconBlock
5, // 1: ethereum.validator.accounts.v2.SignRequest.attestation_data:type_name -> ethereum.eth.v1alpha1.AttestationData
6, // 2: ethereum.validator.accounts.v2.SignRequest.aggregate_attestation_and_proof:type_name -> ethereum.eth.v1alpha1.AggregateAttestationAndProof
7, // 3: ethereum.validator.accounts.v2.SignRequest.exit:type_name -> ethereum.eth.v1alpha1.VoluntaryExit
8, // 4: ethereum.validator.accounts.v2.SignRequest.block_altair:type_name -> ethereum.eth.v1alpha1.BeaconBlockAltair
9, // 5: ethereum.validator.accounts.v2.SignRequest.sync_aggregator_selection_data:type_name -> ethereum.eth.v1alpha1.SyncAggregatorSelectionData
10, // 6: ethereum.validator.accounts.v2.SignRequest.contribution_and_proof:type_name -> ethereum.eth.v1alpha1.ContributionAndProof
11, // 7: ethereum.validator.accounts.v2.SignRequest.block_bellatrix:type_name -> ethereum.eth.v1alpha1.BeaconBlockBellatrix
12, // 8: ethereum.validator.accounts.v2.SignRequest.blinded_block_bellatrix:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix
13, // 9: ethereum.validator.accounts.v2.SignRequest.registration:type_name -> ethereum.eth.v1alpha1.ValidatorRegistrationV1
14, // 10: ethereum.validator.accounts.v2.SignRequest.block_capella:type_name -> ethereum.eth.v1alpha1.BeaconBlockCapella
15, // 11: ethereum.validator.accounts.v2.SignRequest.blinded_block_capella:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockCapella
8, // 0: ethereum.validator.accounts.v2.SignRequest.block:type_name -> ethereum.eth.v1alpha1.BeaconBlock
9, // 1: ethereum.validator.accounts.v2.SignRequest.attestation_data:type_name -> ethereum.eth.v1alpha1.AttestationData
10, // 2: ethereum.validator.accounts.v2.SignRequest.aggregate_attestation_and_proof:type_name -> ethereum.eth.v1alpha1.AggregateAttestationAndProof
11, // 3: ethereum.validator.accounts.v2.SignRequest.exit:type_name -> ethereum.eth.v1alpha1.VoluntaryExit
12, // 4: ethereum.validator.accounts.v2.SignRequest.block_altair:type_name -> ethereum.eth.v1alpha1.BeaconBlockAltair
13, // 5: ethereum.validator.accounts.v2.SignRequest.sync_aggregator_selection_data:type_name -> ethereum.eth.v1alpha1.SyncAggregatorSelectionData
14, // 6: ethereum.validator.accounts.v2.SignRequest.contribution_and_proof:type_name -> ethereum.eth.v1alpha1.ContributionAndProof
15, // 7: ethereum.validator.accounts.v2.SignRequest.block_bellatrix:type_name -> ethereum.eth.v1alpha1.BeaconBlockBellatrix
16, // 8: ethereum.validator.accounts.v2.SignRequest.blinded_block_bellatrix:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockBellatrix
17, // 9: ethereum.validator.accounts.v2.SignRequest.registration:type_name -> ethereum.eth.v1alpha1.ValidatorRegistrationV1
18, // 10: ethereum.validator.accounts.v2.SignRequest.block_capella:type_name -> ethereum.eth.v1alpha1.BeaconBlockCapella
19, // 11: ethereum.validator.accounts.v2.SignRequest.blinded_block_capella:type_name -> ethereum.eth.v1alpha1.BlindedBeaconBlockCapella
0, // 12: ethereum.validator.accounts.v2.SignResponse.status:type_name -> ethereum.validator.accounts.v2.SignResponse.Status
16, // 13: ethereum.validator.accounts.v2.RemoteSigner.ListValidatingPublicKeys:input_type -> google.protobuf.Empty
2, // 14: ethereum.validator.accounts.v2.RemoteSigner.Sign:input_type -> ethereum.validator.accounts.v2.SignRequest
1, // 15: ethereum.validator.accounts.v2.RemoteSigner.ListValidatingPublicKeys:output_type -> ethereum.validator.accounts.v2.ListPublicKeysResponse
3, // 16: ethereum.validator.accounts.v2.RemoteSigner.Sign:output_type -> ethereum.validator.accounts.v2.SignResponse
15, // [15:17] is the sub-list for method output_type
13, // [13:15] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension type_name
13, // [13:13] is the sub-list for extension extendee
0, // [0:13] is the sub-list for field type_name
5, // 13: ethereum.validator.accounts.v2.ProposerOptionPayload.builder:type_name -> ethereum.validator.accounts.v2.BuilderConfig
7, // 14: ethereum.validator.accounts.v2.ProposerSettingsPayload.proposer_config:type_name -> ethereum.validator.accounts.v2.ProposerSettingsPayload.ProposerConfigEntry
4, // 15: ethereum.validator.accounts.v2.ProposerSettingsPayload.default_config:type_name -> ethereum.validator.accounts.v2.ProposerOptionPayload
4, // 16: ethereum.validator.accounts.v2.ProposerSettingsPayload.ProposerConfigEntry.value:type_name -> ethereum.validator.accounts.v2.ProposerOptionPayload
20, // 17: ethereum.validator.accounts.v2.RemoteSigner.ListValidatingPublicKeys:input_type -> google.protobuf.Empty
2, // 18: ethereum.validator.accounts.v2.RemoteSigner.Sign:input_type -> ethereum.validator.accounts.v2.SignRequest
1, // 19: ethereum.validator.accounts.v2.RemoteSigner.ListValidatingPublicKeys:output_type -> ethereum.validator.accounts.v2.ListPublicKeysResponse
3, // 20: ethereum.validator.accounts.v2.RemoteSigner.Sign:output_type -> ethereum.validator.accounts.v2.SignResponse
19, // [19:21] is the sub-list for method output_type
17, // [17:19] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_proto_prysm_v1alpha1_validator_client_keymanager_proto_init() }
@@ -755,6 +978,42 @@ func file_proto_prysm_v1alpha1_validator_client_keymanager_proto_init() {
return nil
}
}
file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProposerOptionPayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BuilderConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProposerSettingsPayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_proto_prysm_v1alpha1_validator_client_keymanager_proto_msgTypes[1].OneofWrappers = []interface{}{
(*SignRequest_Block)(nil),
@@ -779,7 +1038,7 @@ func file_proto_prysm_v1alpha1_validator_client_keymanager_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_prysm_v1alpha1_validator_client_keymanager_proto_rawDesc,
NumEnums: 1,
NumMessages: 3,
NumMessages: 7,
NumExtensions: 0,
NumServices: 1,
},

View File

@@ -107,3 +107,22 @@ message SignResponse {
// same conventions.
Status status = 2;
}
// ProposerOptionPayload is a property of ProposerSettingsPayload
message ProposerOptionPayload {
string fee_recipient = 1;
BuilderConfig builder = 2;
}
// BuilderConfig is a property of ProposerOptionPayload
message BuilderConfig {
bool enabled = 1;
uint64 gas_limit = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v4/consensus-types/validator.Uint64"];
repeated string relays = 3;
}
// ProposerSettingsPayload is used to unmarshal files sent from the validator flag as well as safe to bolt db bucket
message ProposerSettingsPayload {
map<string, ProposerOptionPayload> proposer_config = 1;
ProposerOptionPayload default_config = 2;
}

View File

@@ -29,9 +29,9 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//crypto/bls:go_default_library",
"//io/file:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/interop:go_default_library",
"//testing/endtoend/helpers:go_default_library",
"//testing/endtoend/params:go_default_library",

View File

@@ -268,6 +268,8 @@ func (node *BeaconNode) Start(ctx context.Context) error {
fmt.Sprintf("--%s=%s", cmdshared.VerbosityFlag.Name, "debug"),
fmt.Sprintf("--%s=%d", flags.BlockBatchLimitBurstFactor.Name, 8),
fmt.Sprintf("--%s=%s", cmdshared.ChainConfigFileFlag.Name, cfgPath),
"--" + cmdshared.ValidatorMonitorIndicesFlag.Name + "=1",
"--" + cmdshared.ValidatorMonitorIndicesFlag.Name + "=2",
"--" + cmdshared.ForceClearDB.Name,
"--" + cmdshared.AcceptTosFlag.Name,
"--" + flags.EnableDebugRPCEndpoints.Name,

View File

@@ -20,8 +20,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validator_service_config "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/io/file"
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/v4/runtime/interop"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
e2e "github.com/prysmaticlabs/prysm/v4/testing/endtoend/params"
@@ -244,8 +244,9 @@ func (v *ValidatorNode) Start(ctx context.Context) error {
beaconRestApiPort = e2e.TestParams.Ports.PrysmBeaconNodeGatewayPort
}
args = append(args, fmt.Sprintf("--%s=http://localhost:%d", flags.BeaconRESTApiProviderFlag.Name, beaconRestApiPort))
args = append(args, fmt.Sprintf("--%s", features.EnableBeaconRESTApi.Name))
args = append(args,
fmt.Sprintf("--%s=http://localhost:%d", flags.BeaconRESTApiProviderFlag.Name, beaconRestApiPort),
fmt.Sprintf("--%s", features.EnableBeaconRESTApi.Name))
}
// Only apply e2e flags to the current branch. New flags may not exist in previous release.
@@ -253,10 +254,11 @@ func (v *ValidatorNode) Start(ctx context.Context) error {
args = append(args, features.E2EValidatorFlags...)
}
if v.config.UseWeb3RemoteSigner {
args = append(args, fmt.Sprintf("--%s=http://localhost:%d", flags.Web3SignerURLFlag.Name, Web3RemoteSignerPort))
// Write the pubkeys as comma separated hex strings with 0x prefix.
// See: https://docs.teku.consensys.net/en/latest/HowTo/External-Signer/Use-External-Signer/
args = append(args, fmt.Sprintf("--%s=%s", flags.Web3SignerPublicValidatorKeysFlag.Name, strings.Join(validatorHexPubKeys, ",")))
args = append(args,
fmt.Sprintf("--%s=http://localhost:%d", flags.Web3SignerURLFlag.Name, Web3RemoteSignerPort),
fmt.Sprintf("--%s=%s", flags.Web3SignerPublicValidatorKeysFlag.Name, strings.Join(validatorHexPubKeys, ",")))
} else {
// When not using remote key signer, use interop keys.
args = append(args,
@@ -338,17 +340,16 @@ func createProposerSettingsPath(pubkeys []string, nodeIdx int) (string, error) {
if len(pubkeys) == 0 {
return "", errors.New("number of validators must be greater than 0")
}
var proposerSettingsPayload validator_service_config.ProposerSettingsPayload
config := make(map[string]*validator_service_config.ProposerOptionPayload)
config := make(map[string]*validatorpb.ProposerOptionPayload)
for i, pubkey := range pubkeys {
config[pubkeys[i]] = &validator_service_config.ProposerOptionPayload{
config[pubkeys[i]] = &validatorpb.ProposerOptionPayload{
FeeRecipient: FeeRecipientFromPubkey(pubkey),
}
}
proposerSettingsPayload = validator_service_config.ProposerSettingsPayload{
proposerSettingsPayload := &validatorpb.ProposerSettingsPayload{
ProposerConfig: config,
DefaultConfig: &validator_service_config.ProposerOptionPayload{
DefaultConfig: &validatorpb.ProposerOptionPayload{
FeeRecipient: DefaultFeeRecipientAddress,
},
}

View File

@@ -37,5 +37,6 @@ go_test(
"//time:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)

View File

@@ -4,6 +4,7 @@ package slots
import (
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
prysmTime "github.com/prysmaticlabs/prysm/v4/time"
)
@@ -104,3 +105,65 @@ func (s *SlotTicker) start(
}
}()
}
// startWithIntervals starts a ticker that emits a tick every slot at the
// prescribed intervals. The caller is responsible to make these intervals increasing and
// less than secondsPerSlot
func (s *SlotTicker) startWithIntervals(
genesisTime time.Time,
until func(time.Time) time.Duration,
after func(time.Duration) <-chan time.Time,
intervals []time.Duration) {
go func() {
slot := Since(genesisTime)
slot++
interval := 0
nextTickTime := startFromTime(genesisTime, slot).Add(intervals[0])
for {
waitTime := until(nextTickTime)
select {
case <-after(waitTime):
s.c <- slot
interval++
if interval == len(intervals) {
interval = 0
slot++
}
nextTickTime = startFromTime(genesisTime, slot).Add(intervals[interval])
case <-s.done:
return
}
}
}()
}
// NewSlotTickerWithIntervals starts and returns a SlotTicker instance that allows
// several offsets of time from genesis,
// Caller is responsible to input the intervals in increasing order and none bigger or equal than
// SecondsPerSlot
func NewSlotTickerWithIntervals(genesisTime time.Time, intervals []time.Duration) *SlotTicker {
if genesisTime.Unix() == 0 {
panic("zero genesis time")
}
if len(intervals) == 0 {
panic("at least one interval has to be entered")
}
slotDuration := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
lastOffset := time.Duration(0)
for _, offset := range intervals {
if offset < lastOffset {
panic("invalid decreasing offsets")
}
if offset >= slotDuration {
panic("invalid ticker offset")
}
lastOffset = offset
}
ticker := &SlotTicker{
c: make(chan primitives.Slot),
done: make(chan struct{}),
}
ticker.startWithIntervals(genesisTime, prysmTime.Until, time.After, intervals)
return ticker
}

View File

@@ -4,7 +4,9 @@ import (
"testing"
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/stretchr/testify/require"
)
var _ Ticker = (*SlotTicker)(nil)
@@ -136,3 +138,49 @@ func TestGetSlotTickerWithOffset_OK(t *testing.T) {
}
}
}
func TestGetSlotTickerWitIntervals(t *testing.T) {
genesisTime := time.Now()
offset := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second / 3
intervals := []time.Duration{offset, 2 * offset}
intervalTicker := NewSlotTickerWithIntervals(genesisTime, intervals)
normalTicker := NewSlotTicker(genesisTime, params.BeaconConfig().SecondsPerSlot)
firstTicked := 0
for {
select {
case <-intervalTicker.C():
// interval ticks starts in second slot
if firstTicked < 2 {
t.Fatal("Expected other ticker to tick first")
}
return
case <-normalTicker.C():
if firstTicked > 1 {
t.Fatal("Expected normal ticker to tick first")
}
firstTicked++
}
}
}
func TestSlotTickerWithIntervalsInputValidation(t *testing.T) {
var genesisTime time.Time
offset := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second / 3
intervals := make([]time.Duration, 0)
panicCall := func() {
NewSlotTickerWithIntervals(genesisTime, intervals)
}
require.Panics(t, panicCall, "zero genesis time")
genesisTime = time.Now()
require.Panics(t, panicCall, "at least one interval has to be entered")
intervals = []time.Duration{2 * offset, offset}
require.Panics(t, panicCall, "invalid decreasing offsets")
intervals = []time.Duration{offset, 4 * offset}
require.Panics(t, panicCall, "invalid ticker offset")
intervals = []time.Duration{4 * offset, offset}
require.Panics(t, panicCall, "invalid ticker offset")
intervals = []time.Duration{offset, 2 * offset}
require.NotPanics(t, panicCall)
}

View File

@@ -16,12 +16,17 @@ import (
// incoming objects. (24 mins with mainnet spec)
const MaxSlotBuffer = uint64(1 << 7)
// startFromTime returns the slot start in terms of genesis time.Time
func startFromTime(genesis time.Time, slot primitives.Slot) time.Time {
duration := time.Second * time.Duration(slot.Mul(params.BeaconConfig().SecondsPerSlot))
return genesis.Add(duration) // lint:ignore uintcast -- Genesis timestamp will not exceed int64 in your lifetime.
}
// StartTime returns the start time in terms of its unix epoch
// value.
func StartTime(genesis uint64, slot primitives.Slot) time.Time {
duration := time.Second * time.Duration(slot.Mul(params.BeaconConfig().SecondsPerSlot))
startTime := time.Unix(int64(genesis), 0).Add(duration) // lint:ignore uintcast -- Genesis timestamp will not exceed int64 in your lifetime.
return startTime
genesisTime := time.Unix(int64(genesis), 0) // lint:ignore uintcast -- Genesis timestamp will not exceed int64 in your lifetime.
return startFromTime(genesisTime, slot)
}
// SinceGenesis returns the number of slots since
@@ -247,3 +252,9 @@ func SecondsSinceSlotStart(s primitives.Slot, genesisTime, timeStamp uint64) (ui
}
return timeStamp - genesisTime - uint64(s)*params.BeaconConfig().SecondsPerSlot, nil
}
// TimeIntoSlot returns the time duration elapsed between the current time and
// the start of the current slot
func TimeIntoSlot(genesisTime uint64) time.Duration {
return time.Since(StartTime(genesisTime, CurrentSlot(genesisTime)))
}

View File

@@ -563,3 +563,9 @@ func TestDuration(t *testing.T) {
})
}
}
func TestTimeIntoSlot(t *testing.T) {
genesisTime := uint64(time.Now().Add(-37 * time.Second).Unix())
require.Equal(t, true, TimeIntoSlot(genesisTime) > 900*time.Millisecond)
require.Equal(t, true, TimeIntoSlot(genesisTime) < 3000*time.Millisecond)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"math"
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -25,7 +26,7 @@ func main() {
flag.Parse()
ctx := context.Background()
cc, err := grpc.DialContext(ctx, *beacon, grpc.WithInsecure())
cc, err := grpc.DialContext(ctx, *beacon, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt64)))
if err != nil {
panic(err)
}
@@ -82,6 +83,8 @@ func wrapBlock(b *v1alpha1.BeaconBlockContainer) interfaces.ReadOnlyBeaconBlock
wb, err = blocks.NewSignedBeaconBlock(bb.AltairBlock)
case *v1alpha1.BeaconBlockContainer_BellatrixBlock:
wb, err = blocks.NewSignedBeaconBlock(bb.BellatrixBlock)
case *v1alpha1.BeaconBlockContainer_CapellaBlock:
wb, err = blocks.NewSignedBeaconBlock(bb.CapellaBlock)
}
if err != nil {
panic("no block")

View File

@@ -128,6 +128,7 @@ go_test(
"//consensus-types/blocks/testing:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/bls/common/mock:go_default_library",
"//encoding/bytesutil:go_default_library",

View File

@@ -53,6 +53,7 @@ func run(ctx context.Context, v iface.Validator) {
log.WithError(err).Fatal("Could not get keymanager")
}
sub := km.SubscribeAccountChanges(accountsChangedChan)
// check if proposer settings is still nil
// Set properties on the beacon node like the fee recipient for validators that are being used & active.
if v.ProposerSettings() != nil {
log.Infof("Validator client started with provided proposer settings that sets options such as fee recipient"+
@@ -117,7 +118,7 @@ func run(ctx context.Context, v iface.Validator) {
if slots.IsEpochStart(slot) && v.ProposerSettings() != nil {
go func() {
//deadline set for end of epoch
// deadline set for end of epoch
epochDeadline := v.SlotDeadline(slot + params.BeaconConfig().SlotsPerEpoch - 1)
if err := v.PushProposerSettings(ctx, km, slot, epochDeadline); err != nil {
log.WithError(err).Warn("Failed to update proposer settings")

View File

@@ -188,10 +188,21 @@ func (v *ValidatorService) Start() {
return
}
// checks db if proposer settings exist if none is provided.
if v.proposerSettings == nil {
settings, err := v.db.ProposerSettings(v.ctx)
if err == nil {
v.proposerSettings = settings
}
}
validatorClient := validatorClientFactory.NewValidatorClient(v.conn)
beaconClient := beaconChainClientFactory.NewBeaconChainClient(v.conn)
valStruct := &validator{
db: v.db,
validatorClient: validatorClientFactory.NewValidatorClient(v.conn),
beaconClient: beaconChainClientFactory.NewBeaconChainClient(v.conn),
validatorClient: validatorClient,
beaconClient: beaconClient,
slashingProtectionClient: slasherClientFactory.NewSlasherClient(v.conn),
node: nodeClientFactory.NewNodeClient(v.conn),
graffiti: v.graffiti,
@@ -218,6 +229,7 @@ func (v *ValidatorService) Start() {
proposerSettings: v.proposerSettings,
walletInitializedChannel: make(chan *wallet.Wallet, 1),
}
// To resolve a race condition at startup due to the interface
// nature of the abstracted block type. We initialize
// the inner type of the feed before hand. So that
@@ -255,17 +267,31 @@ func (v *ValidatorService) InteropKeysConfig() *local.InteropKeymanagerConfig {
return v.interopKeysConfig
}
// Keymanager returns the underlying keymanager in the validator
func (v *ValidatorService) Keymanager() (keymanager.IKeymanager, error) {
return v.validator.Keymanager()
}
// ProposerSettings returns a deep copy of the underlying proposer settings in the validator
func (v *ValidatorService) ProposerSettings() *validatorserviceconfig.ProposerSettings {
return v.validator.ProposerSettings()
settings := v.validator.ProposerSettings()
if settings != nil {
return settings.Clone()
}
return nil
}
func (v *ValidatorService) SetProposerSettings(settings *validatorserviceconfig.ProposerSettings) {
// SetProposerSettings sets the proposer settings on the validator service as well as the underlying validator
func (v *ValidatorService) SetProposerSettings(ctx context.Context, settings *validatorserviceconfig.ProposerSettings) error {
if v.db == nil {
return errors.New("db is not set")
}
if err := v.db.SaveProposerSettings(ctx, settings); err != nil {
return err
}
v.proposerSettings = settings
v.validator.SetProposerSettings(settings)
return nil
}
// ConstructDialOptions constructs a list of grpc dial options

View File

@@ -22,6 +22,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
validatorType "github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
blsmock "github.com/prysmaticlabs/prysm/v4/crypto/bls/common/mock"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
@@ -1672,7 +1673,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validatorType.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
})

View File

@@ -5,9 +5,10 @@ go_library(
srcs = ["interface.go"],
importpath = "github.com/prysmaticlabs/prysm/v4/validator/db/iface",
# Other packages must use github.com/prysmaticlabs/prysm/v4/validator/db.Database alias.
visibility = ["//validator/db:__subpackages__"],
visibility = ["//validator:__subpackages__"],
deps = [
"//config/fieldparams:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/primitives:go_default_library",
"//monitoring/backup:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -6,6 +6,7 @@ import (
"io"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/monitoring/backup"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -62,4 +63,11 @@ type ValidatorDB interface {
// Graffiti ordered index related methods
SaveGraffitiOrderedIndex(ctx context.Context, index uint64) error
GraffitiOrderedIndex(ctx context.Context, fileHash [32]byte) (uint64, error)
// ProposerSettings related methods
ProposerSettings(context.Context) (*validatorServiceConfig.ProposerSettings, error)
ProposerSettingsExists(ctx context.Context) (bool, error)
UpdateProposerSettingsDefault(context.Context, *validatorServiceConfig.ProposerOption) error
UpdateProposerSettingsForPubkey(context.Context, [fieldparams.BLSPubkeyLength]byte, *validatorServiceConfig.ProposerOption) error
SaveProposerSettings(ctx context.Context, settings *validatorServiceConfig.ProposerSettings) error
}

View File

@@ -15,6 +15,7 @@ go_library(
"migration_optimal_attester_protection.go",
"migration_source_target_epochs_bucket.go",
"proposer_protection.go",
"proposer_settings.go",
"prune_attester_protection.go",
"schema.go",
],
@@ -29,6 +30,7 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
@@ -36,6 +38,7 @@ go_library(
"//monitoring/tracing:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/slashings:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
@@ -43,6 +46,7 @@ go_library(
"@com_github_sirupsen_logrus//:go_default_library",
"@io_etcd_go_bbolt//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)
@@ -59,18 +63,23 @@ go_test(
"migration_optimal_attester_protection_test.go",
"migration_source_target_epochs_bucket_test.go",
"proposer_protection_test.go",
"proposer_settings_test.go",
"prune_attester_protection_test.go",
],
embed = [":go_default_library"],
deps = [
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@io_etcd_go_bbolt//:go_default_library",

View File

@@ -152,6 +152,7 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
pubKeysBucket,
migrationsBucket,
graffitiBucket,
proposerSettingsBucket,
)
}); err != nil {
return nil, err

View File

@@ -0,0 +1,132 @@
package kv
import (
"context"
"fmt"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
"google.golang.org/protobuf/proto"
)
// NoProposerSettingsFound is an error thrown when no settings are found in bucket
var NoProposerSettingsFound = errors.New("no proposer settings found in bucket")
// UpdateProposerSettingsForPubkey updates the existing settings for an internal representation of the proposers settings file at a particular public key
func (s *Store) UpdateProposerSettingsForPubkey(ctx context.Context, pubkey [fieldparams.BLSPubkeyLength]byte, options *validatorServiceConfig.ProposerOption) error {
_, span := trace.StartSpan(ctx, "validator.db.UpdateProposerSettingsForPubkey")
defer span.End()
err := s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
b := bkt.Get(proposerSettingsKey)
if len(b) == 0 {
return fmt.Errorf("no proposer settings found in bucket")
}
to := &validatorpb.ProposerSettingsPayload{}
if err := proto.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal proposer settings")
}
settings, err := validatorServiceConfig.ToSettings(to)
if err != nil {
return errors.Wrap(err, "failed to convert payload to proposer settings")
}
if settings.ProposeConfig == nil {
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
}
settings.ProposeConfig[pubkey] = options
m, err := proto.Marshal(settings.ToPayload())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}
return bkt.Put(proposerSettingsKey, m)
})
return err
}
// UpdateProposerSettingsDefault updates the existing default settings for proposer settings
func (s *Store) UpdateProposerSettingsDefault(ctx context.Context, options *validatorServiceConfig.ProposerOption) error {
_, span := trace.StartSpan(ctx, "validator.db.UpdateProposerSettingsDefault")
defer span.End()
if options == nil {
return errors.New("proposer settings option was empty")
}
if options.FeeRecipientConfig == nil {
return errors.New("fee recipient cannot be empty")
}
err := s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
b := bkt.Get(proposerSettingsKey)
if len(b) == 0 {
return NoProposerSettingsFound
}
to := &validatorpb.ProposerSettingsPayload{}
if err := proto.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal proposer settings")
}
settings, err := validatorServiceConfig.ToSettings(to)
if err != nil {
return errors.Wrap(err, "failed to convert payload to proposer settings")
}
settings.DefaultConfig = options
m, err := proto.Marshal(settings.ToPayload())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}
return bkt.Put(proposerSettingsKey, m)
})
return err
}
// ProposerSettings gets the current proposer settings
func (s *Store) ProposerSettings(ctx context.Context) (*validatorServiceConfig.ProposerSettings, error) {
_, span := trace.StartSpan(ctx, "validator.db.ProposerSettings")
defer span.End()
to := &validatorpb.ProposerSettingsPayload{}
if err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
b := bkt.Get(proposerSettingsKey)
if len(b) == 0 {
return NoProposerSettingsFound
}
if err := proto.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal proposer settings")
}
return nil
}); err != nil {
return nil, err
}
return validatorServiceConfig.ToSettings(to)
}
// ProposerSettingsExists returns true or false if the settings exist or not
func (s *Store) ProposerSettingsExists(ctx context.Context) (bool, error) {
ps, err := s.ProposerSettings(ctx)
if err != nil {
if errors.Is(err, NoProposerSettingsFound) {
return false, nil
}
return false, err
}
if ps == nil {
return false, nil
}
return true, nil
}
// SaveProposerSettings saves the entire proposer setting overriding the existing settings
func (s *Store) SaveProposerSettings(ctx context.Context, settings *validatorServiceConfig.ProposerSettings) error {
_, span := trace.StartSpan(ctx, "validator.db.SaveProposerSettings")
defer span.End()
return s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
m, err := proto.Marshal(settings.ToPayload())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}
return bkt.Put(proposerSettingsKey, m)
})
}

View File

@@ -0,0 +1,106 @@
package kv
import (
"context"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestStore_ProposerSettings_ReadAndWrite(t *testing.T) {
t.Run("save to db in full", func(t *testing.T) {
ctx := context.Background()
db := setupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
err = db.SaveProposerSettings(ctx, settings)
require.NoError(t, err)
dbSettings, err := db.ProposerSettings(ctx)
require.NoError(t, err)
require.DeepEqual(t, settings, dbSettings)
})
t.Run("update default settings then update at specific key", func(t *testing.T) {
ctx := context.Background()
db := setupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorServiceConfig.ProposerSettings{
DefaultConfig: &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
err = db.SaveProposerSettings(ctx, settings)
require.NoError(t, err)
upatedDefault := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x9995733c5af9B61374A128e6F85f553aF09ff89B"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
}
err = db.UpdateProposerSettingsDefault(ctx, upatedDefault)
require.NoError(t, err)
dbSettings, err := db.ProposerSettings(ctx)
require.NoError(t, err)
require.NotNil(t, dbSettings)
require.DeepEqual(t, dbSettings.DefaultConfig, upatedDefault)
option := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
}
err = db.UpdateProposerSettingsForPubkey(ctx, bytesutil.ToBytes48(key1), option)
require.NoError(t, err)
newSettings, err := db.ProposerSettings(ctx)
require.NoError(t, err)
require.NotNil(t, newSettings)
require.DeepEqual(t, newSettings.DefaultConfig, upatedDefault)
op, ok := newSettings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, ok, true)
require.DeepEqual(t, op, option)
})
}

View File

@@ -37,4 +37,8 @@ var (
// Graffiti ordered index and hash keys
graffitiOrderedIndexKey = []byte("graffiti-ordered-index")
graffitiFileHashKey = []byte("graffiti-file-hash")
// ProposerSettings stores the encoded proposer settings file
proposerSettingsBucket = []byte("proposer-settings-bucket")
proposerSettingsKey = []byte("proposer-settings")
)

View File

@@ -11,10 +11,12 @@ go_test(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//validator/accounts:go_default_library",
"//validator/db/testing:go_default_library",
"//validator/keymanager:go_default_library",
"//validator/keymanager/remote-web3signer:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
@@ -45,6 +47,7 @@ go_library(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//container/slice:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
@@ -60,6 +63,7 @@ go_library(
"//runtime/version:go_default_library",
"//validator/accounts/wallet:go_default_library",
"//validator/client:go_default_library",
"//validator/db/iface:go_default_library",
"//validator/db/kv:go_default_library",
"//validator/graffiti:go_default_library",
"//validator/keymanager/local:go_default_library",
@@ -75,7 +79,7 @@ go_library(
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@in_gopkg_yaml_v2//:go_default_library",
"@io_k8s_apimachinery//pkg/util/yaml:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
],
)

View File

@@ -35,6 +35,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/container/slice"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/io/file"
@@ -50,6 +51,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/v4/validator/client"
"github.com/prysmaticlabs/prysm/v4/validator/db/iface"
"github.com/prysmaticlabs/prysm/v4/validator/db/kv"
g "github.com/prysmaticlabs/prysm/v4/validator/graffiti"
"github.com/prysmaticlabs/prysm/v4/validator/keymanager/local"
@@ -60,7 +62,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"google.golang.org/protobuf/encoding/protojson"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/util/yaml"
)
// ValidatorClient defines an instance of an Ethereum validator that manages
@@ -406,7 +408,7 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error {
return err
}
bpc, err := proposerSettings(c.cliCtx)
bpc, err := proposerSettings(c.cliCtx, c.db)
if err != nil {
return err
}
@@ -488,8 +490,8 @@ func Web3SignerConfig(cliCtx *cli.Context) (*remoteweb3signer.SetupConfig, error
return web3signerConfig, nil
}
func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSettings, error) {
var fileConfig *validatorServiceConfig.ProposerSettingsPayload
func proposerSettings(cliCtx *cli.Context, db iface.ValidatorDB) (*validatorServiceConfig.ProposerSettings, error) {
var fileConfig *validatorpb.ProposerSettingsPayload
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) && cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
return nil, errors.New("cannot specify both " + flags.ProposerSettingsFlag.Name + " and " + flags.ProposerSettingsURLFlag.Name)
@@ -504,11 +506,11 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
if err != nil {
return nil, err
}
fileConfig = &validatorServiceConfig.ProposerSettingsPayload{
fileConfig = &validatorpb.ProposerSettingsPayload{
ProposerConfig: nil,
DefaultConfig: &validatorServiceConfig.ProposerOptionPayload{
FeeRecipient: suggestedFee,
BuilderConfig: builderConfig,
DefaultConfig: &validatorpb.ProposerOptionPayload{
FeeRecipient: suggestedFee,
Builder: builderConfig.ToPayload(),
},
}
}
@@ -541,7 +543,10 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
if !common.IsHexAddress(fileConfig.DefaultConfig.FeeRecipient) {
return nil, errors.New("default fileConfig fee recipient is not a valid eth1 address")
}
psExists, err := db.ProposerSettingsExists(cliCtx.Context)
if err != nil {
return nil, err
}
if err := warnNonChecksummedAddress(fileConfig.DefaultConfig.FeeRecipient); err != nil {
return nil, err
}
@@ -549,7 +554,7 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(fileConfig.DefaultConfig.FeeRecipient),
},
BuilderConfig: fileConfig.DefaultConfig.BuilderConfig,
BuilderConfig: validatorServiceConfig.ToBuilderConfig(fileConfig.DefaultConfig.Builder),
}
if vpSettings.DefaultConfig.BuilderConfig == nil {
builderConfig, err := BuilderSettingsFromFlags(cliCtx)
@@ -563,6 +568,13 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
vpSettings.DefaultConfig.BuilderConfig.GasLimit = reviewGasLimit(vpSettings.DefaultConfig.BuilderConfig.GasLimit)
}
if psExists {
// if settings exist update the default
if err := db.UpdateProposerSettingsDefault(cliCtx.Context, vpSettings.DefaultConfig); err != nil {
return nil, err
}
}
if fileConfig.ProposerConfig != nil {
vpSettings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
for key, option := range fileConfig.ProposerConfig {
@@ -582,30 +594,43 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
if err := warnNonChecksummedAddress(option.FeeRecipient); err != nil {
return nil, err
}
if option.BuilderConfig != nil {
option.BuilderConfig.GasLimit = reviewGasLimit(option.BuilderConfig.GasLimit)
if option.Builder != nil {
option.Builder.GasLimit = reviewGasLimit(option.Builder.GasLimit)
} else {
builderConfig, err := BuilderSettingsFromFlags(cliCtx)
if err != nil {
return nil, err
}
option.BuilderConfig = builderConfig
option.Builder = builderConfig.ToPayload()
}
vpSettings.ProposeConfig[bytesutil.ToBytes48(decodedKey)] = &validatorServiceConfig.ProposerOption{
o := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(option.FeeRecipient),
},
BuilderConfig: option.BuilderConfig,
BuilderConfig: validatorServiceConfig.ToBuilderConfig(option.Builder),
}
pubkeyB := bytesutil.ToBytes48(decodedKey)
vpSettings.ProposeConfig[pubkeyB] = o
}
if psExists {
// override the existing saved settings if providing values via fileConfig.ProposerConfig
if err := db.SaveProposerSettings(cliCtx.Context, vpSettings); err != nil {
return nil, err
}
}
}
if !psExists {
// if no proposer settings ever existed in the db just save the settings
if err := db.SaveProposerSettings(cliCtx.Context, vpSettings); err != nil {
return nil, err
}
}
return vpSettings, nil
}
func BuilderSettingsFromFlags(cliCtx *cli.Context) (*validatorServiceConfig.BuilderConfig, error) {
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
gasLimit := validatorServiceConfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
gasLimit := validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
sgl := cliCtx.String(flags.BuilderGasLimitFlag.Name)
if sgl != "" {
@@ -613,7 +638,7 @@ func BuilderSettingsFromFlags(cliCtx *cli.Context) (*validatorServiceConfig.Buil
if err != nil {
return nil, errors.New("Gas Limit is not a uint64")
}
gasLimit = reviewGasLimit(validatorServiceConfig.Uint64(gl))
gasLimit = reviewGasLimit(validator.Uint64(gl))
}
return &validatorServiceConfig.BuilderConfig{
Enabled: true,
@@ -637,10 +662,10 @@ func warnNonChecksummedAddress(feeRecipient string) error {
return nil
}
func reviewGasLimit(gasLimit validatorServiceConfig.Uint64) validatorServiceConfig.Uint64 {
func reviewGasLimit(gasLimit validator.Uint64) validator.Uint64 {
// sets gas limit to default if not defined or set to 0
if gasLimit == 0 {
return validatorServiceConfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
return validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
}
// TODO(10810): add in warning for ranges
return gasLimit

View File

@@ -16,10 +16,12 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/validator/accounts"
dbTest "github.com/prysmaticlabs/prysm/v4/validator/db/testing"
"github.com/prysmaticlabs/prysm/v4/validator/keymanager"
remoteweb3signer "github.com/prysmaticlabs/prysm/v4/validator/keymanager/remote-web3signer"
logtest "github.com/sirupsen/logrus/hooks/test"
@@ -279,7 +281,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
bytesutil.ToBytes48(key2): {
@@ -288,7 +290,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(35000000),
GasLimit: validator.Uint64(35000000),
},
},
},
@@ -298,7 +300,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(40000000),
GasLimit: validator.Uint64(40000000),
},
},
}
@@ -364,7 +366,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: false,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
@@ -410,7 +412,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
@@ -494,7 +496,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
@@ -504,7 +506,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
@@ -532,7 +534,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
@@ -542,7 +544,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
@@ -569,7 +571,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validatorserviceconfig.Uint64(40000000),
GasLimit: validator.Uint64(40000000),
},
},
},
@@ -579,7 +581,7 @@ func TestProposerSettings(t *testing.T) {
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: false,
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
@@ -677,7 +679,8 @@ func TestProposerSettings(t *testing.T) {
set.Bool(flags.EnableBuilderFlag.Name, true, "")
}
cliCtx := cli.NewContext(&app, set, nil)
got, err := proposerSettings(cliCtx)
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
got, err := proposerSettings(cliCtx, validatorDB)
if tt.wantErr != "" {
require.ErrorContains(t, tt.wantErr, err)
return
@@ -695,10 +698,11 @@ func TestProposerSettings(t *testing.T) {
// return an error if the user is using builder settings without any default fee recipient
func TestProposerSettings_EnableBuilder_noFeeRecipient(t *testing.T) {
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool(flags.EnableBuilderFlag.Name, true, "")
cliCtx := cli.NewContext(&app, set, nil)
_, err := proposerSettings(cliCtx)
_, err := proposerSettings(cliCtx, validatorDB)
require.ErrorContains(t, "can only be used when a default fee recipient is present on the validator client", err)
}

View File

@@ -0,0 +1,3 @@
{
"test": "123441"
}

View File

@@ -28,6 +28,7 @@ go_library(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -101,6 +102,7 @@ go_test(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
@@ -117,6 +119,7 @@ go_test(
"//validator/accounts/wallet:go_default_library",
"//validator/client:go_default_library",
"//validator/db/kv:go_default_library",
"//validator/db/testing:go_default_library",
"//validator/keymanager:go_default_library",
"//validator/keymanager/derived:go_default_library",
"//validator/keymanager/remote-web3signer:go_default_library",

View File

@@ -12,6 +12,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -403,14 +404,15 @@ func (s *Server) GetGasLimit(_ context.Context, req *ethpbservice.PubkeyRequest)
Pubkey: validatorKey,
},
}
if s.validatorService.ProposerSettings() != nil {
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
settings := s.validatorService.ProposerSettings()
if settings != nil {
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
if proposerOption.BuilderConfig != nil {
resp.Data.GasLimit = uint64(proposerOption.BuilderConfig.GasLimit)
return resp, nil
}
} else if s.validatorService.ProposerSettings().DefaultConfig != nil && s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig != nil {
} else if settings.DefaultConfig != nil && settings.DefaultConfig.BuilderConfig != nil {
resp.Data.GasLimit = uint64(s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig.GasLimit)
return resp, nil
}
@@ -424,63 +426,43 @@ func (s *Server) SetGasLimit(ctx context.Context, req *ethpbservice.SetGasLimitR
if s.validatorService == nil {
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
}
validatorKey := req.Pubkey
if err := validatePublicKey(validatorKey); err != nil {
return nil, status.Error(codes.FailedPrecondition, err.Error())
}
var pBuilderConfig *validatorServiceConfig.BuilderConfig
if s.validatorService.ProposerSettings() != nil &&
s.validatorService.ProposerSettings().DefaultConfig != nil &&
s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig != nil {
// Make a copy of BuilderConfig from DefaultConfig (thus "*" then "&"), so when we change GasLimit, we do not mess up with
// "DefaultConfig.BuilderConfig".
bo := *s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig
pBuilderConfig = &bo
pBuilderConfig.GasLimit = validatorServiceConfig.Uint64(req.GasLimit)
} else {
// No default BuilderConfig to copy from, just create one and set "GasLimit", but keep "Enabled" to "false".
pBuilderConfig = &validatorServiceConfig.BuilderConfig{
Enabled: false,
GasLimit: validatorServiceConfig.Uint64(req.GasLimit),
Relays: []string{},
settings := s.validatorService.ProposerSettings()
if settings == nil {
return &empty.Empty{}, status.Errorf(codes.FailedPrecondition, "no proposer settings were found to update")
} else if settings.ProposeConfig == nil {
if settings.DefaultConfig == nil || settings.DefaultConfig.BuilderConfig == nil || !settings.DefaultConfig.BuilderConfig.Enabled {
return &empty.Empty{}, status.Errorf(codes.FailedPrecondition, "gas limit changes only apply when builder is enabled")
}
}
pOption := validatorServiceConfig.ProposerOption{
FeeRecipientConfig: nil,
BuilderConfig: pBuilderConfig,
}
if s.validatorService.ProposerSettings() == nil {
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
},
DefaultConfig: nil,
})
} else if s.validatorService.ProposerSettings().ProposeConfig == nil {
settings := s.validatorService.ProposerSettings()
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &pOption
s.validatorService.SetProposerSettings(settings)
option := settings.DefaultConfig.Clone()
option.BuilderConfig.GasLimit = validator.Uint64(req.GasLimit)
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = option
} else {
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
if proposerOption.BuilderConfig == nil {
proposerOption.BuilderConfig = pBuilderConfig
if proposerOption.BuilderConfig == nil || !proposerOption.BuilderConfig.Enabled {
return &empty.Empty{}, status.Errorf(codes.FailedPrecondition, "gas limit changes only apply when builder is enabled")
} else {
proposerOption.BuilderConfig.GasLimit = validatorServiceConfig.Uint64(req.GasLimit)
proposerOption.BuilderConfig.GasLimit = validator.Uint64(req.GasLimit)
}
} else {
s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &pOption
if settings.DefaultConfig == nil {
return &empty.Empty{}, status.Errorf(codes.FailedPrecondition, "gas limit changes only apply when builder is enabled")
}
option := settings.DefaultConfig.Clone()
option.BuilderConfig.GasLimit = validator.Uint64(req.GasLimit)
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = option
}
}
// save the settings
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set proposer settings: %v", err)
}
// override the 200 success with 202 according to the specs
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "202")); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)
@@ -507,7 +489,11 @@ func (s *Server) DeleteGasLimit(ctx context.Context, req *ethpbservice.DeleteGas
proposerOption.BuilderConfig.GasLimit = proposerSettings.DefaultConfig.BuilderConfig.GasLimit
} else {
// Fallback to using global default.
proposerOption.BuilderConfig.GasLimit = validatorServiceConfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
proposerOption.BuilderConfig.GasLimit = validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
}
// save the settings
if err := s.validatorService.SetProposerSettings(ctx, proposerSettings); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set proposer settings: %v", err)
}
// Successfully deleted gas limit (reset to proposer config default or global default).
// Return with success http code "204".
@@ -553,11 +539,11 @@ func (s *Server) ListFeeRecipientByPubkey(ctx context.Context, req *ethpbservice
// If fee recipient is defined in default configuration, use it
if proposerSettings != nil && proposerSettings.DefaultConfig != nil && proposerSettings.DefaultConfig.FeeRecipientConfig != nil {
finalResp.Data.Ethaddress = s.validatorService.ProposerSettings().DefaultConfig.FeeRecipientConfig.FeeRecipient.Bytes()
finalResp.Data.Ethaddress = proposerSettings.DefaultConfig.FeeRecipientConfig.FeeRecipient.Bytes()
return finalResp, nil
}
// Else, use the one defined in beacon node
// Else, use the one defined in beacon node TODO: remove this with db removal
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, &eth.FeeRecipientByPubKeyRequest{
PublicKey: validatorKey,
})
@@ -593,10 +579,10 @@ func (s *Server) SetFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.
return nil, status.Error(
codes.InvalidArgument, "Fee recipient is not a valid Ethereum address")
}
settings := s.validatorService.ProposerSettings()
switch {
case s.validatorService.ProposerSettings() == nil:
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
case settings == nil:
settings = &validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
@@ -606,15 +592,12 @@ func (s *Server) SetFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.
},
},
DefaultConfig: nil,
})
case s.validatorService.ProposerSettings().ProposeConfig == nil:
builderConfig := &validatorServiceConfig.BuilderConfig{}
settings := s.validatorService.ProposerSettings()
if settings.DefaultConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig
}
case settings.ProposeConfig == nil:
var builderConfig *validatorServiceConfig.BuilderConfig
if settings.DefaultConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig.Clone()
}
settings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
@@ -623,34 +606,29 @@ func (s *Server) SetFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.
BuilderConfig: builderConfig,
},
}
s.validatorService.SetProposerSettings(settings)
default:
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found && proposerOption != nil {
proposerOption.FeeRecipientConfig = &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
}
} else {
settings := s.validatorService.ProposerSettings()
var builderConfig = &validatorServiceConfig.BuilderConfig{}
if settings.DefaultConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig
builderConfig = settings.DefaultConfig.BuilderConfig.Clone()
}
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: builderConfig,
}
s.validatorService.SetProposerSettings(settings)
}
}
// save the settings
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set proposer settings: %v", err)
}
// override the 200 success with 202 according to the specs
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "202")); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)
@@ -679,6 +657,11 @@ func (s *Server) DeleteFeeRecipientByPubkey(ctx context.Context, req *ethpbservi
}
}
// save the settings
if err := s.validatorService.SetProposerSettings(ctx, settings); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set proposer settings: %v", err)
}
// override the 200 success with 204 according to the specs
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "204")); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)

View File

@@ -17,6 +17,7 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v4/config/validator/service"
"github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service"
@@ -31,6 +32,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/v4/validator/client"
"github.com/prysmaticlabs/prysm/v4/validator/db/kv"
dbtest "github.com/prysmaticlabs/prysm/v4/validator/db/testing"
"github.com/prysmaticlabs/prysm/v4/validator/keymanager"
"github.com/prysmaticlabs/prysm/v4/validator/keymanager/derived"
remoteweb3signer "github.com/prysmaticlabs/prysm/v4/validator/keymanager/remote-web3signer"
@@ -998,15 +1000,18 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
validatorDB := dbtest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
// save a default here
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
ValDB: validatorDB,
})
require.NoError(t, err)
s := &Server{
validatorService: vs,
beaconNodeValidatorClient: beaconClient,
valDB: validatorDB,
}
_, err = s.SetFeeRecipientByPubkey(ctx, &ethpbservice.SetFeeRecipientByPubkeyRequest{Pubkey: byteval, Ethaddress: common.HexToAddress(tt.args).Bytes()})
@@ -1097,12 +1102,15 @@ func TestServer_DeleteFeeRecipientByPubkey(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
validatorDB := dbtest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
ValDB: validatorDB,
})
require.NoError(t, err)
s := &Server{
validatorService: vs,
valDB: validatorDB,
}
_, err = s.DeleteFeeRecipientByPubkey(ctx, &ethpbservice.PubkeyRequest{Pubkey: byteval})
require.NoError(t, err)
@@ -1207,7 +1215,6 @@ func TestServer_GetGasLimit(t *testing.T) {
func TestServer_SetGasLimit(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
beaconClient := validatormock.NewMockValidatorClient(ctrl)
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
@@ -1231,20 +1238,16 @@ func TestServer_SetGasLimit(t *testing.T) {
pubkey []byte
newGasLimit uint64
proposerSettings *validatorserviceconfig.ProposerSettings
w []want
w []*want
beaconReturn *beaconResp
wantErr string
}{
{
name: "ProposerSettings is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: nil,
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
wantErr: "no proposer settings were found to update",
},
{
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig is nil",
@@ -1254,12 +1257,7 @@ func TestServer_SetGasLimit(t *testing.T) {
ProposeConfig: nil,
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
wantErr: "gas limit changes only apply when builder is enabled",
},
{
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig.BuilderConfig is nil",
@@ -1271,12 +1269,7 @@ func TestServer_SetGasLimit(t *testing.T) {
BuilderConfig: nil,
},
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
wantErr: "gas limit changes only apply when builder is enabled",
},
{
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is nil AND ProposerSettings.DefaultConfig is nil",
@@ -1290,12 +1283,7 @@ func TestServer_SetGasLimit(t *testing.T) {
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
wantErr: "gas limit changes only apply when builder is enabled",
},
{
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is defined AND ProposerSettings.DefaultConfig is nil",
@@ -1309,12 +1297,7 @@ func TestServer_SetGasLimit(t *testing.T) {
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
wantErr: "gas limit changes only apply when builder is enabled",
},
{
name: "ProposerSettings.ProposeConfig is NOT defined for pubkey, BuilderConfig is defined AND ProposerSettings.DefaultConfig is nil",
@@ -1322,23 +1305,19 @@ func TestServer_SetGasLimit(t *testing.T) {
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: 12345,
},
},
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 12345,
},
{
pubkey: pubkey2,
gaslimit: 9999,
},
w: []*want{{
pubkey2,
9999,
},
},
},
{
@@ -1347,19 +1326,20 @@ func TestServer_SetGasLimit(t *testing.T) {
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: nil,
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
},
},
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
w: []*want{{
pubkey1,
9999,
},
},
},
}
@@ -1367,15 +1347,17 @@ func TestServer_SetGasLimit(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
validatorDB := dbtest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
ValDB: validatorDB,
})
require.NoError(t, err)
s := &Server{
validatorService: vs,
beaconNodeValidatorClient: beaconClient,
valDB: validatorDB,
}
if tt.beaconReturn != nil {
@@ -1386,10 +1368,13 @@ func TestServer_SetGasLimit(t *testing.T) {
}
_, err = s.SetGasLimit(ctx, &ethpbservice.SetGasLimitRequest{Pubkey: tt.pubkey, GasLimit: tt.newGasLimit})
require.NoError(t, err)
for _, w := range tt.w {
assert.Equal(t, w.gaslimit, uint64(s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(w.pubkey)].BuilderConfig.GasLimit))
if tt.wantErr != "" {
require.ErrorContains(t, tt.wantErr, err)
} else {
require.NoError(t, err)
for _, w := range tt.w {
assert.Equal(t, w.gaslimit, uint64(s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(w.pubkey)].BuilderConfig.GasLimit))
}
}
})
}
@@ -1432,11 +1417,11 @@ func TestServer_DeleteGasLimit(t *testing.T) {
params.BeaconConfig().DefaultBuilderGasLimit = originBeaconChainGasLimit
}()
globalDefaultGasLimit := validatorserviceconfig.Uint64(0xbbdd)
globalDefaultGasLimit := validator.Uint64(0xbbdd)
type want struct {
pubkey []byte
gaslimit validatorserviceconfig.Uint64
gaslimit validator.Uint64
}
tests := []struct {
@@ -1452,14 +1437,14 @@ func TestServer_DeleteGasLimit(t *testing.T) {
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(987654321)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(123456789)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(123456789)},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(5555)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(5555)},
},
},
wantError: nil,
@@ -1467,11 +1452,11 @@ func TestServer_DeleteGasLimit(t *testing.T) {
{
pubkey: pubkey1,
// After deletion, use DefaultConfig.BuilderConfig.GasLimit.
gaslimit: validatorserviceconfig.Uint64(5555),
gaslimit: validator.Uint64(5555),
},
{
pubkey: pubkey2,
gaslimit: validatorserviceconfig.Uint64(123456789),
gaslimit: validator.Uint64(123456789),
},
},
},
@@ -1481,10 +1466,10 @@ func TestServer_DeleteGasLimit(t *testing.T) {
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(987654321)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(123456789)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(123456789)},
},
},
},
@@ -1497,7 +1482,7 @@ func TestServer_DeleteGasLimit(t *testing.T) {
},
{
pubkey: pubkey2,
gaslimit: validatorserviceconfig.Uint64(123456789),
gaslimit: validator.Uint64(123456789),
},
},
},
@@ -1507,7 +1492,7 @@ func TestServer_DeleteGasLimit(t *testing.T) {
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validatorserviceconfig.Uint64(987654321)},
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
},
},
@@ -1516,7 +1501,7 @@ func TestServer_DeleteGasLimit(t *testing.T) {
// pubkey1's gaslimit is unaffected
{
pubkey: pubkey1,
gaslimit: validatorserviceconfig.Uint64(987654321),
gaslimit: validator.Uint64(987654321),
},
},
},
@@ -1531,12 +1516,15 @@ func TestServer_DeleteGasLimit(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
validatorDB := dbtest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
ValDB: validatorDB,
})
require.NoError(t, err)
s := &Server{
validatorService: vs,
valDB: validatorDB,
}
// Set up global default value for builder gas limit.
params.BeaconConfig().DefaultBuilderGasLimit = uint64(globalDefaultGasLimit)