Skip to content

Commit

Permalink
Merge pull request #178 from attestantio/config-helpers
Browse files Browse the repository at this point in the history
Ensure all relevant beacon nodes receive proposal preparations.
  • Loading branch information
mcdee authored Feb 7, 2024
2 parents 21b7ec9 + d1aa3d8 commit f375add
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 68 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
1.8.0:
- reject block proposals with 0 fee recipient
- ensure all relevant beacon nodes receive proposal preparations

1.8.0-beta.1:
- ensure relay configuration inherits all configuration values as expected
Expand Down
45 changes: 17 additions & 28 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,17 @@ func startServices(ctx context.Context,
}
}

// We need to submit proposal preparations to all nodes that are acting as beacon block proposers.
nodeAddresses := util.BeaconNodeAddressesForProposing()
proposalPreparationsSubmitters := make([]eth2client.ProposalPreparationsSubmitter, 0, len(nodeAddresses))
for _, address := range nodeAddresses {
client, err := fetchClient(ctx, monitor, address)
if err != nil {
return nil, nil, errors.Wrap(err, fmt.Sprintf("failed to fetch client %s for proposal preparation submitter", address))
}
proposalPreparationsSubmitters = append(proposalPreparationsSubmitters, client.(eth2client.ProposalPreparationsSubmitter))
}

var proposalPreparer proposalpreparer.Service
if bellatrixCapable {
log.Trace().Msg("Starting proposals preparer")
Expand All @@ -376,7 +387,7 @@ func startServices(ctx context.Context,
standardproposalpreparer.WithMonitor(monitor),
standardproposalpreparer.WithChainTimeService(chainTime),
standardproposalpreparer.WithValidatingAccountsProvider(accountManager.(accountmanager.ValidatingAccountsProvider)),
standardproposalpreparer.WithProposalPreparationsSubmitter(submitter.(eth2client.ProposalPreparationsSubmitter)),
standardproposalpreparer.WithProposalPreparationsSubmitters(proposalPreparationsSubmitters),
standardproposalpreparer.WithExecutionConfigProvider(blockRelay.(blockrelay.ExecutionConfigProvider)),
)
if err != nil {
Expand All @@ -385,16 +396,7 @@ func startServices(ctx context.Context,
}

// The events provider for the controller should only use beacon nodes that are used for attestation data.
var eventsBeaconNodeAddresses []string
switch {
case viper.Get("strategies.attestationdata.best") != nil:
eventsBeaconNodeAddresses = util.BeaconNodeAddresses("strategies.attestationdata.best")
case viper.Get("strategies.attestationdata.first") != nil:
eventsBeaconNodeAddresses = util.BeaconNodeAddresses("strategies.attestationdata.first")
default:
eventsBeaconNodeAddresses = util.BeaconNodeAddresses("strategies.attestationdata")
}
eventsConsensusClient, err := fetchMultiClient(ctx, monitor, eventsBeaconNodeAddresses)
eventsConsensusClient, err := fetchMultiClient(ctx, monitor, util.BeaconNodeAddressesForAttesting())
if err != nil {
return nil, nil, errors.Wrap(err, "failed to fetch multiclient for controller")
}
Expand Down Expand Up @@ -1632,27 +1634,14 @@ func startBlockRelay(ctx context.Context,

// We also need to submit validator registrations to all nodes that are acting as blinded beacon block proposers, as
// some of them use the registration as part of the condition to decide if the blinded block should be called or not.
bestBeaconNodeAddresses := util.BeaconNodeAddresses("strategies.blindedbeaconblockproposal.best")
firstBeaconNodeAddresses := util.BeaconNodeAddresses("strategies.blindedbeaconblockproposal.first")
secondaryValidatorRegistrationsSubmitters := make([]eth2client.ValidatorRegistrationsSubmitter, 0, len(bestBeaconNodeAddresses)+len(firstBeaconNodeAddresses))
clients := make(map[string]struct{})
for _, address := range bestBeaconNodeAddresses {
nodeAddresses := util.BeaconNodeAddressesForProposing()
secondaryValidatorRegistrationsSubmitters := make([]eth2client.ValidatorRegistrationsSubmitter, 0, len(nodeAddresses))
for _, address := range nodeAddresses {
client, err := fetchClient(ctx, monitor, address)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to fetch client %s for blinded beacon block proposal strategy", address))
return nil, errors.Wrap(err, fmt.Sprintf("failed to fetch client %s for secondary validator registration", address))
}
secondaryValidatorRegistrationsSubmitters = append(secondaryValidatorRegistrationsSubmitters, client.(eth2client.ValidatorRegistrationsSubmitter))
clients[address] = struct{}{}
}
for _, address := range firstBeaconNodeAddresses {
if _, exists := clients[address]; !exists {
client, err := fetchClient(ctx, monitor, address)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to fetch client %s for blinded beacon block proposal strategy", address))
}
secondaryValidatorRegistrationsSubmitters = append(secondaryValidatorRegistrationsSubmitters, client.(eth2client.ValidatorRegistrationsSubmitter))
clients[address] = struct{}{}
}
}

var fallbackFeeRecipient bellatrix.ExecutionAddress
Expand Down
24 changes: 12 additions & 12 deletions services/proposalpreparer/standard/parameters.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Attestant Limited.
// Copyright © 2022, 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand Down Expand Up @@ -27,12 +27,12 @@ import (
)

type parameters struct {
logLevel zerolog.Level
monitor metrics.Service
chainTimeService chaintime.Service
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
proposalPreparationsSubmitter eth2client.ProposalPreparationsSubmitter
executionConfigProvider blockrelay.ExecutionConfigProvider
logLevel zerolog.Level
monitor metrics.Service
chainTimeService chaintime.Service
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
proposalPreparationsSubmitters []eth2client.ProposalPreparationsSubmitter
executionConfigProvider blockrelay.ExecutionConfigProvider
}

// Parameter is the interface for service parameters.
Expand Down Expand Up @@ -74,10 +74,10 @@ func WithValidatingAccountsProvider(provider accountmanager.ValidatingAccountsPr
})
}

// WithProposalPreparationsSubmitter sets the proposal preparations submitter.
func WithProposalPreparationsSubmitter(submitter eth2client.ProposalPreparationsSubmitter) Parameter {
// WithProposalPreparationsSubmitters sets the proposal preparations submitters.
func WithProposalPreparationsSubmitters(submitters []eth2client.ProposalPreparationsSubmitter) Parameter {
return parameterFunc(func(p *parameters) {
p.proposalPreparationsSubmitter = submitter
p.proposalPreparationsSubmitters = submitters
})
}

Expand Down Expand Up @@ -109,8 +109,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.validatingAccountsProvider == nil {
return nil, errors.New("no validating accounts provider specified")
}
if parameters.proposalPreparationsSubmitter == nil {
return nil, errors.New("no proposal preparations submitter specified")
if len(parameters.proposalPreparationsSubmitters) == 0 {
return nil, errors.New("no proposal preparations submitters specified")
}
if parameters.executionConfigProvider == nil {
return nil, errors.New("no execution configuration provider specified")
Expand Down
18 changes: 9 additions & 9 deletions services/proposalpreparer/standard/service.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Attestant Limited.
// Copyright © 2022, 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand Down Expand Up @@ -27,10 +27,10 @@ import (

// Service is a proposal preparer.
type Service struct {
chainTimeService chaintime.Service
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
proposalPreparationsSubmitter eth2client.ProposalPreparationsSubmitter
executionConfigProvider blockrelay.ExecutionConfigProvider
chainTimeService chaintime.Service
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
proposalPreparationsSubmitters []eth2client.ProposalPreparationsSubmitter
executionConfigProvider blockrelay.ExecutionConfigProvider
}

// module-wide log.
Expand All @@ -54,10 +54,10 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
}

s := &Service{
chainTimeService: parameters.chainTimeService,
validatingAccountsProvider: parameters.validatingAccountsProvider,
proposalPreparationsSubmitter: parameters.proposalPreparationsSubmitter,
executionConfigProvider: parameters.executionConfigProvider,
chainTimeService: parameters.chainTimeService,
validatingAccountsProvider: parameters.validatingAccountsProvider,
proposalPreparationsSubmitters: parameters.proposalPreparationsSubmitters,
executionConfigProvider: parameters.executionConfigProvider,
}

return s, nil
Expand Down
30 changes: 21 additions & 9 deletions services/proposalpreparer/standard/service_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Attestant Limited.
// Copyright © 2022, 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand All @@ -18,6 +18,7 @@ import (
"testing"
"time"

eth2client "github.com/attestantio/go-eth2-client"
"github.com/attestantio/vouch/mock"
mockaccountmanager "github.com/attestantio/vouch/services/accountmanager/mock"
mockblockrelay "github.com/attestantio/vouch/services/blockrelay/mock"
Expand Down Expand Up @@ -45,7 +46,7 @@ func TestService(t *testing.T) {
require.NoError(t, err)

mockValidatingAccountsProvider := mockaccountmanager.NewValidatingAccountsProvider()
mockProposalPreparationsSubmitter := mock.NewProposalPreparationsSubmitter()
mockProposalPreparationsSubmitters := []eth2client.ProposalPreparationsSubmitter{mock.NewProposalPreparationsSubmitter()}
mockBlockRelay := mockblockrelay.New()

prometheusMetrics, err := prometheusmetrics.New(ctx,
Expand All @@ -67,7 +68,7 @@ func TestService(t *testing.T) {
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithProposalPreparationsSubmitter(mockProposalPreparationsSubmitter),
standard.WithProposalPreparationsSubmitters(mockProposalPreparationsSubmitters),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
err: "problem with parameters: no monitor specified",
Expand All @@ -77,7 +78,7 @@ func TestService(t *testing.T) {
params: []standard.Parameter{
standard.WithLogLevel(zerolog.Disabled),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithProposalPreparationsSubmitter(mockProposalPreparationsSubmitter),
standard.WithProposalPreparationsSubmitters(mockProposalPreparationsSubmitters),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
err: "problem with parameters: no chain time service specified",
Expand All @@ -87,7 +88,7 @@ func TestService(t *testing.T) {
params: []standard.Parameter{
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithProposalPreparationsSubmitter(mockProposalPreparationsSubmitter),
standard.WithProposalPreparationsSubmitters(mockProposalPreparationsSubmitters),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
err: "problem with parameters: no validating accounts provider specified",
Expand All @@ -98,19 +99,30 @@ func TestService(t *testing.T) {
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithProposalPreparationsSubmitter(mockProposalPreparationsSubmitter),
standard.WithProposalPreparationsSubmitters(mockProposalPreparationsSubmitters),
},
err: "problem with parameters: no execution configuration provider specified",
},
{
name: "ProposalPreparationsSubmitterMissing",
name: "ProposalPreparationsSubmittersMissing",
params: []standard.Parameter{
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
err: "problem with parameters: no proposal preparations submitter specified",
err: "problem with parameters: no proposal preparations submitters specified",
},
{
name: "ProposalPreparationsSubmittersempty",
params: []standard.Parameter{
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithProposalPreparationsSubmitters([]eth2client.ProposalPreparationsSubmitter{}),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
err: "problem with parameters: no proposal preparations submitters specified",
},
{
name: "Good",
Expand All @@ -119,7 +131,7 @@ func TestService(t *testing.T) {
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockValidatingAccountsProvider),
standard.WithProposalPreparationsSubmitter(mockProposalPreparationsSubmitter),
standard.WithProposalPreparationsSubmitters(mockProposalPreparationsSubmitters),
standard.WithExecutionConfigProvider(mockBlockRelay),
},
},
Expand Down
22 changes: 15 additions & 7 deletions services/proposalpreparer/standard/updatepreparations.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Attestant Limited.
// Copyright © 2022, 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand All @@ -18,6 +18,7 @@ import (
"fmt"
"time"

eth2client "github.com/attestantio/go-eth2-client"
apiv1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
Expand Down Expand Up @@ -99,12 +100,19 @@ func (s *Service) updateProposalPreparations(ctx context.Context,
))
defer span.End()

if err := s.proposalPreparationsSubmitter.SubmitProposalPreparations(ctx, proposalPreparations); err != nil {
proposalPreparationCompleted(started, epoch, "failed")
log.Error().Err(err).Msg("Failed to update proposal preparations")
return
failed := 0
for _, proposalPreparationsSubmitter := range s.proposalPreparationsSubmitters {
if err := proposalPreparationsSubmitter.SubmitProposalPreparations(ctx, proposalPreparations); err != nil {
failed++
log.Error().Str("client", proposalPreparationsSubmitter.(eth2client.Service).Address()).Err(err).Msg("Failed to update proposal preparations")
// Do not exit here; we want to attempt all proposal preparations.
}
}

log.Trace().Dur("elapsed", time.Since(started)).Msg("Submitted proposal preparations")
proposalPreparationCompleted(started, epoch, "succeeded")
if failed > 0 {
proposalPreparationCompleted(started, epoch, "failed")
} else {
log.Trace().Dur("elapsed", time.Since(started)).Msg("Submitted proposal preparations")
proposalPreparationCompleted(started, epoch, "succeeded")
}
}
7 changes: 4 additions & 3 deletions services/proposalpreparer/standard/updatepreparations_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2022 Attestant Limited.
// Copyright © 2022, 2024 Attestant Limited.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand All @@ -18,6 +18,7 @@ import (
"testing"
"time"

eth2client "github.com/attestantio/go-eth2-client"
"github.com/attestantio/vouch/mock"
mockaccountmanager "github.com/attestantio/vouch/services/accountmanager/mock"
mockblockrelay "github.com/attestantio/vouch/services/blockrelay/mock"
Expand Down Expand Up @@ -55,7 +56,7 @@ func TestUpdatePreparations(t *testing.T) {
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockaccountmanager.NewErroringValidatingAccountsProvider()),
standard.WithProposalPreparationsSubmitter(mock.NewProposalPreparationsSubmitter()),
standard.WithProposalPreparationsSubmitters([]eth2client.ProposalPreparationsSubmitter{mock.NewProposalPreparationsSubmitter()}),
standard.WithExecutionConfigProvider(mockblockrelay.New()),
},
err: "failed to obtain validating accounts: error",
Expand All @@ -66,7 +67,7 @@ func TestUpdatePreparations(t *testing.T) {
standard.WithLogLevel(zerolog.Disabled),
standard.WithChainTimeService(chainTime),
standard.WithValidatingAccountsProvider(mockaccountmanager.NewValidatingAccountsProvider()),
standard.WithProposalPreparationsSubmitter(mock.NewProposalPreparationsSubmitter()),
standard.WithProposalPreparationsSubmitters([]eth2client.ProposalPreparationsSubmitter{mock.NewProposalPreparationsSubmitter()}),
standard.WithExecutionConfigProvider(mockblockrelay.New()),
},
},
Expand Down
Loading

0 comments on commit f375add

Please sign in to comment.