Update dependencies

This commit is contained in:
Jim McDonald 2020-11-26 20:32:04 +00:00
parent e66a4a3613
commit 925e69fb9a
No known key found for this signature in database
GPG Key ID: 89CEB61B2AD2A5E7
24 changed files with 385 additions and 259 deletions

2
go.mod
View File

@ -6,7 +6,7 @@ require (
cloud.google.com/go v0.72.0 // indirect
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/attestantio/dirk v0.9.6
github.com/attestantio/go-eth2-client v0.6.14
github.com/attestantio/go-eth2-client v0.6.15
github.com/aws/aws-sdk-go v1.35.35
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321
github.com/goccy/go-yaml v1.8.4 // indirect

2
go.sum
View File

@ -83,6 +83,8 @@ github.com/attestantio/go-eth2-client v0.6.13 h1:n2mN6ZUJcKbNKh/rhE8la7IB5Z8V2Tg
github.com/attestantio/go-eth2-client v0.6.13/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.14 h1:zP/zP8CKygHVfbxV1ppwWBqbI8yfs3paBsv7Nccx34Q=
github.com/attestantio/go-eth2-client v0.6.14/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.15 h1:GNkiSF2Dqp6qahMXMW8r8Wy61WEvytnAM+rEyutdfv8=
github.com/attestantio/go-eth2-client v0.6.15/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=

12
main.go
View File

@ -328,7 +328,7 @@ func startServices(ctx context.Context, majordomo majordomo.Service) error {
standardattester.WithProcessConcurrency(viper.GetInt64("process-concurrency")),
standardattester.WithSlotsPerEpochProvider(eth2Client.(eth2client.SlotsPerEpochProvider)),
standardattester.WithAttestationDataProvider(attestationDataProvider),
standardattester.WithAttestationSubmitter(submitterStrategy.(submitter.AttestationSubmitter)),
standardattester.WithAttestationsSubmitter(submitterStrategy.(submitter.AttestationsSubmitter)),
standardattester.WithMonitor(monitor.(metrics.AttestationMonitor)),
standardattester.WithValidatingAccountsProvider(accountManager.(accountmanager.ValidatingAccountsProvider)),
standardattester.WithBeaconAttestationsSigner(signerSvc.(signer.BeaconAttestationsSigner)),
@ -751,10 +751,10 @@ func selectSubmitterStrategy(ctx context.Context, monitor metrics.Service, eth2C
var submitter submitter.Service
var err error
switch viper.GetString("submitter.style") {
case "all":
case "all", "multinode":
log.Info().Msg("Starting multinode submitter strategy")
beaconBlockSubmitters := make(map[string]eth2client.BeaconBlockSubmitter)
attestationSubmitters := make(map[string]eth2client.AttestationSubmitter)
attestationsSubmitters := make(map[string]eth2client.AttestationsSubmitter)
aggregateAttestationSubmitters := make(map[string]eth2client.AggregateAttestationsSubmitter)
beaconCommitteeSubscriptionsSubmitters := make(map[string]eth2client.BeaconCommitteeSubscriptionsSubmitter)
for _, address := range viper.GetStringSlice("submitter.beacon-node-addresses") {
@ -763,7 +763,7 @@ func selectSubmitterStrategy(ctx context.Context, monitor metrics.Service, eth2C
return nil, errors.Wrap(err, fmt.Sprintf("failed to fetch client %s for submitter strategy", address))
}
beaconBlockSubmitters[address] = client.(eth2client.BeaconBlockSubmitter)
attestationSubmitters[address] = client.(eth2client.AttestationSubmitter)
attestationsSubmitters[address] = client.(eth2client.AttestationsSubmitter)
aggregateAttestationSubmitters[address] = client.(eth2client.AggregateAttestationsSubmitter)
beaconCommitteeSubscriptionsSubmitters[address] = client.(eth2client.BeaconCommitteeSubscriptionsSubmitter)
}
@ -772,7 +772,7 @@ func selectSubmitterStrategy(ctx context.Context, monitor metrics.Service, eth2C
multinodesubmitter.WithProcessConcurrency(viper.GetInt64("process-concurrency")),
multinodesubmitter.WithLogLevel(logLevel(viper.GetString("submitter.log-level"))),
multinodesubmitter.WithBeaconBlockSubmitters(beaconBlockSubmitters),
multinodesubmitter.WithAttestationSubmitters(attestationSubmitters),
multinodesubmitter.WithAttestationsSubmitters(attestationsSubmitters),
multinodesubmitter.WithAggregateAttestationsSubmitters(aggregateAttestationSubmitters),
multinodesubmitter.WithBeaconCommitteeSubscriptionsSubmitters(beaconCommitteeSubscriptionsSubmitters),
)
@ -782,7 +782,7 @@ func selectSubmitterStrategy(ctx context.Context, monitor metrics.Service, eth2C
immediatesubmitter.WithLogLevel(logLevel(viper.GetString("submitter.log-level"))),
immediatesubmitter.WithClientMonitor(monitor.(metrics.ClientMonitor)),
immediatesubmitter.WithBeaconBlockSubmitter(eth2Client.(eth2client.BeaconBlockSubmitter)),
immediatesubmitter.WithAttestationSubmitter(eth2Client.(eth2client.AttestationSubmitter)),
immediatesubmitter.WithAttestationsSubmitter(eth2Client.(eth2client.AttestationsSubmitter)),
immediatesubmitter.WithBeaconCommitteeSubscriptionsSubmitter(eth2Client.(eth2client.BeaconCommitteeSubscriptionsSubmitter)),
immediatesubmitter.WithAggregateAttestationsSubmitter(eth2Client.(eth2client.AggregateAttestationsSubmitter)),
)

View File

@ -107,29 +107,29 @@ func (m *ErroringSlotsPerEpochProvider) SlotsPerEpoch(ctx context.Context) (uint
return 0, errors.New("error")
}
// AttestationSubmitter is a mock for eth2client.AttestationSubmitter.
type AttestationSubmitter struct{}
// AttestationsSubmitter is a mock for eth2client.AttestationsSubmitter.
type AttestationsSubmitter struct{}
// NewAttestationSubmitter returns a mock attestation submitter.
func NewAttestationSubmitter() eth2client.AttestationSubmitter {
return &AttestationSubmitter{}
// NewAttestationsSubmitter returns a mock attestations submitter.
func NewAttestationsSubmitter() eth2client.AttestationsSubmitter {
return &AttestationsSubmitter{}
}
// SubmitAttestation is a mock.
func (m *AttestationSubmitter) SubmitAttestation(ctx context.Context, attestation *spec.Attestation) error {
// SubmitAttestations is a mock.
func (m *AttestationsSubmitter) SubmitAttestations(ctx context.Context, attestation []*spec.Attestation) error {
return nil
}
// ErroringAttestationSubmitter is a mock for eth2client.AttestationSubmitter that returns errors.
type ErroringAttestationSubmitter struct{}
// ErroringAttestationsSubmitter is a mock for eth2client.AttestationsSubmitter that returns errors.
type ErroringAttestationsSubmitter struct{}
// NewErroringAttestationSubmitter returns a mock attestation submitter.
func NewErroringAttestationSubmitter() eth2client.AttestationSubmitter {
return &ErroringAttestationSubmitter{}
// NewErroringAttestationsSubmitter returns a mock attestation submitter.
func NewErroringAttestationsSubmitter() eth2client.AttestationsSubmitter {
return &ErroringAttestationsSubmitter{}
}
// SubmitAttestation is a mock.
func (m *ErroringAttestationSubmitter) SubmitAttestation(ctx context.Context, attestation *spec.Attestation) error {
// SubmitAttestations is a mock.
func (m *ErroringAttestationsSubmitter) SubmitAttestations(ctx context.Context, attestations []*spec.Attestation) error {
return errors.New("error")
}

View File

@ -29,7 +29,7 @@ type parameters struct {
monitor metrics.AttestationMonitor
slotsPerEpochProvider eth2client.SlotsPerEpochProvider
attestationDataProvider eth2client.AttestationDataProvider
attestationSubmitter submitter.AttestationSubmitter
attestationsSubmitter submitter.AttestationsSubmitter
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
beaconAttestationsSigner signer.BeaconAttestationsSigner
}
@ -73,10 +73,10 @@ func WithAttestationDataProvider(provider eth2client.AttestationDataProvider) Pa
})
}
// WithAttestationSubmitter sets the attestation submitter.
func WithAttestationSubmitter(submitter submitter.AttestationSubmitter) Parameter {
// WithAttestationsSubmitter sets the attestations submitter.
func WithAttestationsSubmitter(submitter submitter.AttestationsSubmitter) Parameter {
return parameterFunc(func(p *parameters) {
p.attestationSubmitter = submitter
p.attestationsSubmitter = submitter
})
}
@ -121,8 +121,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.attestationDataProvider == nil {
return nil, errors.New("no attestation data provider specified")
}
if parameters.attestationSubmitter == nil {
return nil, errors.New("no attestation submitter specified")
if parameters.attestationsSubmitter == nil {
return nil, errors.New("no attestations submitter specified")
}
if parameters.monitor == nil {
return nil, errors.New("no monitor specified")

View File

@ -17,7 +17,6 @@ import (
"bytes"
"context"
"fmt"
"sync"
"time"
eth2client "github.com/attestantio/go-eth2-client"
@ -27,7 +26,6 @@ import (
"github.com/attestantio/vouch/services/metrics"
"github.com/attestantio/vouch/services/signer"
"github.com/attestantio/vouch/services/submitter"
"github.com/attestantio/vouch/util"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/rs/zerolog"
@ -42,7 +40,7 @@ type Service struct {
slotsPerEpoch uint64
validatingAccountsProvider accountmanager.ValidatingAccountsProvider
attestationDataProvider eth2client.AttestationDataProvider
attestationSubmitter submitter.AttestationSubmitter
attestationsSubmitter submitter.AttestationsSubmitter
beaconAttestationsSigner signer.BeaconAttestationsSigner
}
@ -73,7 +71,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
slotsPerEpoch: slotsPerEpoch,
validatingAccountsProvider: parameters.validatingAccountsProvider,
attestationDataProvider: parameters.attestationDataProvider,
attestationSubmitter: parameters.attestationSubmitter,
attestationsSubmitter: parameters.attestationsSubmitter,
beaconAttestationsSigner: parameters.beaconAttestationsSigner,
}
@ -201,49 +199,41 @@ func (s *Service) attest(
}
log.Trace().Dur("elapsed", time.Since(started)).Msg("Signed")
// Submit the attestations.
// Create the attestations.
zeroSig := spec.BLSSignature{}
attestations := make([]*spec.Attestation, len(sigs))
_, err = util.Scatter(len(sigs), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) {
for i := offset; i < offset+entries; i++ {
log := log.With().Uint64("slot", uint64(duty.Slot())).Uint64("validator_index", uint64(validatorIndices[i])).Logger()
if bytes.Equal(sigs[i][:], zeroSig[:]) {
log.Warn().Msg("No signature for validator; not creating attestation")
continue
}
aggregationBits := bitfield.NewBitlist(committeeSizes[i])
aggregationBits.SetBitAt(uint64(validatorCommitteeIndices[i]), true)
attestation := &spec.Attestation{
AggregationBits: aggregationBits,
Data: &spec.AttestationData{
Slot: duty.Slot(),
Index: committeeIndices[i],
BeaconBlockRoot: data.BeaconBlockRoot,
Source: &spec.Checkpoint{
Epoch: data.Source.Epoch,
Root: data.Source.Root,
},
Target: &spec.Checkpoint{
Epoch: data.Target.Epoch,
Root: data.Target.Root,
},
},
}
copy(attestation.Signature[:], sigs[i][:])
if err := s.attestationSubmitter.SubmitAttestation(ctx, attestation); err != nil {
log.Warn().Err(err).Msg("Failed to submit attestation")
continue
}
attestations[i] = attestation
s.monitor.AttestationCompleted(started, "succeeded")
attestations := make([]*spec.Attestation, 0, len(sigs))
for i := range sigs {
if bytes.Equal(sigs[i][:], zeroSig[:]) {
log.Warn().Msg("No signature for validator; not creating attestation")
continue
}
return nil, nil
})
if err != nil {
log.Error().Err(err).Msg("Failed to scatter submit")
aggregationBits := bitfield.NewBitlist(committeeSizes[i])
aggregationBits.SetBitAt(uint64(validatorCommitteeIndices[i]), true)
attestation := &spec.Attestation{
AggregationBits: aggregationBits,
Data: &spec.AttestationData{
Slot: duty.Slot(),
Index: committeeIndices[i],
BeaconBlockRoot: data.BeaconBlockRoot,
Source: &spec.Checkpoint{
Epoch: data.Source.Epoch,
Root: data.Source.Root,
},
Target: &spec.Checkpoint{
Epoch: data.Target.Epoch,
Root: data.Target.Root,
},
},
}
copy(attestation.Signature[:], sigs[i][:])
attestations = append(attestations, attestation)
}
log.Trace().Dur("elapsed", time.Since(started)).Msg("Submitted")
// Submit the attestations.
if err := s.attestationsSubmitter.SubmitAttestations(ctx, attestations); err != nil {
log.Warn().Err(err).Msg("Failed to submit attestations")
}
log.Trace().Dur("elapsed", time.Since(started)).Msg("Submitted attestations")
return attestations, nil
}

View File

@ -117,7 +117,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
return nil, errors.Wrap(err, "failed to obtain active validator indices for the current epoch")
}
if len(validatorIndices) != s.activeValidators {
log.Info().Int("old_valdiators", s.activeValidators).Int("new_validators", len(validatorIndices)).Msg("Change in number of active validators")
log.Info().Int("old_validators", s.activeValidators).Int("new_validators", len(validatorIndices)).Msg("Change in number of active validators")
s.activeValidators = len(validatorIndices)
}
nextEpochAccounts, nextEpochValidatorIndices, err := s.accountsAndIndicesForEpoch(ctx, epoch+1)
@ -162,8 +162,6 @@ func (s *Service) startTickers(ctx context.Context) error {
// Wait for genesis.
log.Info().Str("genesis", fmt.Sprintf("%v", genesisTime)).Msg("Waiting for genesis")
time.Sleep(time.Until(genesisTime))
// Give it another half second to let the beacon node be ready.
time.Sleep(500 * time.Millisecond)
}
// Start epoch tickers.

View File

@ -0,0 +1,59 @@
// Copyright © 2020 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package standard
import (
"context"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// sign signs a root, using protected methods if possible.
func (s *Service) sign(ctx context.Context,
account e2wtypes.Account,
root spec.Root,
domain spec.Domain,
) (
spec.BLSSignature,
error,
) {
var sig e2types.Signature
if protectingSigner, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner); isProtectingSigner {
var err error
sig, err = protectingSigner.SignGeneric(ctx, root[:], domain[:])
if err != nil {
return spec.BLSSignature{}, err
}
} else {
container := spec.SigningData{
ObjectRoot: root,
Domain: domain,
}
root, err := container.HashTreeRoot()
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to generate hash tree root")
}
sig, err = account.(e2wtypes.AccountSigner).Sign(ctx, root[:])
if err != nil {
return spec.BLSSignature{}, err
}
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
}

View File

@ -38,12 +38,10 @@ func (s *Service) SignAggregateAndProof(ctx context.Context,
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon aggregate and proof")
}
sig, err := account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, aggregateAndProofRoot[:], domain[:])
sig, err := s.sign(ctx, account, aggregateAndProofRoot, domain)
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to aggregate and proof")
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
return sig, nil
}

View File

@ -35,7 +35,6 @@ func (s *Service) SignBeaconAttestation(ctx context.Context,
spec.BLSSignature,
error,
) {
domain, err := s.domainProvider.Domain(ctx,
s.beaconAttesterDomainType,
spec.Epoch(slot/s.slotsPerEpoch))
@ -43,20 +42,44 @@ func (s *Service) SignBeaconAttestation(ctx context.Context,
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
}
sig, err := account.(e2wtypes.AccountProtectingSigner).SignBeaconAttestation(ctx,
uint64(slot),
uint64(committeeIndex),
blockRoot[:],
uint64(sourceEpoch),
sourceRoot[:],
uint64(targetEpoch),
targetRoot[:],
domain[:])
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon attestation")
var sig spec.BLSSignature
if protectingSigner, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner); isProtectingSigner {
signature, err := protectingSigner.SignBeaconAttestation(ctx,
uint64(slot),
uint64(committeeIndex),
blockRoot[:],
uint64(sourceEpoch),
sourceRoot[:],
uint64(targetEpoch),
targetRoot[:],
domain[:])
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon attestation")
}
copy(sig[:], signature.Marshal())
} else {
attestation := &spec.AttestationData{
Slot: slot,
Index: committeeIndex,
BeaconBlockRoot: blockRoot,
Source: &spec.Checkpoint{
Epoch: sourceEpoch,
Root: sourceRoot,
},
Target: &spec.Checkpoint{
Epoch: targetEpoch,
Root: targetRoot,
},
}
root, err := attestation.HashTreeRoot()
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to generate hash tree root")
}
sig, err = s.sign(ctx, account, root, domain)
if err != nil {
return spec.BLSSignature{}, err
}
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
return sig, nil
}

View File

@ -36,7 +36,7 @@ func (s *Service) SignBeaconAttestations(ctx context.Context,
[]spec.BLSSignature,
error,
) {
span, ctx := opentracing.StartSpanFromContext(ctx, "dirk.SignBeaconAttestations")
span, ctx := opentracing.StartSpanFromContext(ctx, "signer.SignBeaconAttestations")
defer span.Finish()
if len(accounts) == 0 {
@ -50,30 +50,51 @@ func (s *Service) SignBeaconAttestations(ctx context.Context,
return nil, errors.Wrap(err, "failed to obtain signature domain for beacon attestation")
}
uintCommitteeIndices := make([]uint64, len(committeeIndices))
for i := range committeeIndices {
uintCommitteeIndices[i] = uint64(committeeIndices[i])
sigs := make([]spec.BLSSignature, len(accounts))
if multiSigner, isMultiSigner := accounts[0].(e2wtypes.AccountProtectingMultiSigner); isMultiSigner {
uintCommitteeIndices := make([]uint64, len(committeeIndices))
for i := range committeeIndices {
uintCommitteeIndices[i] = uint64(committeeIndices[i])
}
signatures, err := multiSigner.SignBeaconAttestations(ctx,
uint64(slot),
accounts,
uintCommitteeIndices,
blockRoot[:],
uint64(sourceEpoch),
sourceRoot[:],
uint64(targetEpoch),
targetRoot[:],
signatureDomain[:],
)
if err != nil {
return nil, errors.Wrap(err, "failed to multisign beacon attestation")
}
for i := range signatures {
if signatures[i] != nil {
copy(sigs[i][:], signatures[i].Marshal())
}
}
} else {
for i := range accounts {
sigs[i], err = s.SignBeaconAttestation(ctx,
accounts[i],
slot,
committeeIndices[i],
blockRoot,
sourceEpoch,
sourceRoot,
targetEpoch,
targetRoot,
)
if err != nil {
return nil, errors.Wrap(err, "failed to sign beacon attestation")
}
}
}
sigs, err := accounts[0].(e2wtypes.AccountProtectingMultiSigner).SignBeaconAttestations(ctx,
uint64(slot),
accounts,
uintCommitteeIndices,
blockRoot[:],
uint64(sourceEpoch),
sourceRoot[:],
uint64(targetEpoch),
targetRoot[:],
signatureDomain[:],
)
if err != nil {
return nil, errors.Wrap(err, "failed to sign beacon attestation")
}
res := make([]spec.BLSSignature, len(sigs))
for i := range sigs {
if sigs[i] != nil {
copy(res[i][:], sigs[i].Marshal())
}
}
return res, nil
return sigs, nil
}

View File

@ -21,7 +21,7 @@ import (
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// SignBeaconBlockProposal signs a beacon block proposal item.
// SignBeaconBlockProposal signs a beacon block proposal.
func (s *Service) SignBeaconBlockProposal(ctx context.Context,
account e2wtypes.Account,
slot spec.Slot,
@ -42,18 +42,36 @@ func (s *Service) SignBeaconBlockProposal(ctx context.Context,
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for beacon proposal")
}
sig, err := account.(e2wtypes.AccountProtectingSigner).SignBeaconProposal(ctx,
uint64(slot),
uint64(proposerIndex),
parentRoot[:],
stateRoot[:],
bodyRoot[:],
domain[:])
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon block proposal")
var sig spec.BLSSignature
if protectingSigner, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner); isProtectingSigner {
signature, err := protectingSigner.SignBeaconProposal(ctx,
uint64(slot),
uint64(proposerIndex),
parentRoot[:],
stateRoot[:],
bodyRoot[:],
domain[:])
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign beacon block proposal")
}
copy(sig[:], signature.Marshal())
} else {
header := &spec.BeaconBlockHeader{
Slot: slot,
ProposerIndex: proposerIndex,
ParentRoot: parentRoot,
StateRoot: stateRoot,
BodyRoot: bodyRoot,
}
root, err := header.HashTreeRoot()
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to generate hash tree root")
}
sig, err = s.sign(ctx, account, root, domain)
if err != nil {
return spec.BLSSignature{}, err
}
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
return sig, nil
}

View File

@ -43,15 +43,13 @@ func (s *Service) SignRANDAOReveal(ctx context.Context,
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for RANDAO reveal")
}
epochBytes := make([]byte, 32)
binary.LittleEndian.PutUint64(epochBytes, uint64(epoch))
var epochBytes spec.Root
binary.LittleEndian.PutUint64(epochBytes[:], uint64(epoch))
sig, err := account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, epochBytes, domain[:])
sig, err := s.sign(ctx, account, epochBytes, domain)
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign RANDO reveal")
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
return sig, nil
}

View File

@ -42,15 +42,13 @@ func (s *Service) SignSlotSelection(ctx context.Context,
return spec.BLSSignature{}, errors.Wrap(err, "failed to obtain signature domain for selection proof")
}
slotBytes := make([]byte, 32)
binary.LittleEndian.PutUint64(slotBytes, uint64(slot))
var slotBytes spec.Root
binary.LittleEndian.PutUint64(slotBytes[:], uint64(slot))
sig, err := account.(e2wtypes.AccountProtectingSigner).SignGeneric(ctx, slotBytes, domain[:])
sig, err := s.sign(ctx, account, slotBytes, domain)
if err != nil {
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign slot")
return spec.BLSSignature{}, errors.Wrap(err, "failed to sign RANDO reveal")
}
var signature spec.BLSSignature
copy(signature[:], sig.Marshal())
return signature, nil
return sig, nil
}

View File

@ -28,7 +28,7 @@ type parameters struct {
logLevel zerolog.Level
clientMonitor metrics.ClientMonitor
beaconBlockSubmitter eth2client.BeaconBlockSubmitter
attestationSubmitter eth2client.AttestationSubmitter
attestationsSubmitter eth2client.AttestationsSubmitter
beaconCommitteeSubscriptionsSubmitter eth2client.BeaconCommitteeSubscriptionsSubmitter
aggregateAttestationsSubmitter eth2client.AggregateAttestationsSubmitter
}
@ -65,10 +65,10 @@ func WithBeaconBlockSubmitter(submitter eth2client.BeaconBlockSubmitter) Paramet
})
}
// WithAttestationSubmitter sets the attestation submitter.
func WithAttestationSubmitter(submitter eth2client.AttestationSubmitter) Parameter {
// WithAttestationsSubmitter sets the attestation submitter.
func WithAttestationsSubmitter(submitter eth2client.AttestationsSubmitter) Parameter {
return parameterFunc(func(p *parameters) {
p.attestationSubmitter = submitter
p.attestationsSubmitter = submitter
})
}
@ -104,8 +104,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if parameters.beaconBlockSubmitter == nil {
return nil, errors.New("no beacon block submitter specified")
}
if parameters.attestationSubmitter == nil {
return nil, errors.New("no attestation submitter specified")
if parameters.attestationsSubmitter == nil {
return nil, errors.New("no attestations submitter specified")
}
if parameters.beaconCommitteeSubscriptionsSubmitter == nil {
return nil, errors.New("no beacon committee subscriptions submitter specified")

View File

@ -30,7 +30,7 @@ import (
// Service is the submitter for signed items.
type Service struct {
clientMonitor metrics.ClientMonitor
attestationSubmitter eth2client.AttestationSubmitter
attestationsSubmitter eth2client.AttestationsSubmitter
beaconBlockSubmitter eth2client.BeaconBlockSubmitter
beaconCommitteeSubscriptionsSubmitter eth2client.BeaconCommitteeSubscriptionsSubmitter
aggregateAttestationsSubmitter eth2client.AggregateAttestationsSubmitter
@ -54,7 +54,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
s := &Service{
clientMonitor: parameters.clientMonitor,
attestationSubmitter: parameters.attestationSubmitter,
attestationsSubmitter: parameters.attestationsSubmitter,
beaconBlockSubmitter: parameters.beaconBlockSubmitter,
beaconCommitteeSubscriptionsSubmitter: parameters.beaconCommitteeSubscriptionsSubmitter,
aggregateAttestationsSubmitter: parameters.aggregateAttestationsSubmitter,
@ -90,27 +90,27 @@ func (s *Service) SubmitBeaconBlock(ctx context.Context, block *spec.SignedBeaco
return nil
}
// SubmitAttestation submits an attestation.
func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attestation) error {
if attestation == nil {
return errors.New("no attestation supplied")
// SubmitAttestations submits multiple attestations.
func (s *Service) SubmitAttestations(ctx context.Context, attestations []*spec.Attestation) error {
if len(attestations) == 0 {
return errors.New("no attestations supplied")
}
started := time.Now()
err := s.attestationSubmitter.SubmitAttestation(ctx, attestation)
if service, isService := s.attestationSubmitter.(eth2client.Service); isService {
s.clientMonitor.ClientOperation(service.Address(), "submit attestation", err == nil, time.Since(started))
err := s.attestationsSubmitter.SubmitAttestations(ctx, attestations)
if service, isService := s.attestationsSubmitter.(eth2client.Service); isService {
s.clientMonitor.ClientOperation(service.Address(), "submit attestations", err == nil, time.Since(started))
} else {
s.clientMonitor.ClientOperation("<unknown>", "submit attestation", err == nil, time.Since(started))
s.clientMonitor.ClientOperation("<unknown>", "submit attestations", err == nil, time.Since(started))
}
if err != nil {
return errors.Wrap(err, "failed to submit attestation")
return errors.Wrap(err, "failed to submit attestations")
}
if e := log.Trace(); e.Enabled() {
data, err := json.Marshal(attestation)
data, err := json.Marshal(attestations)
if err == nil {
e.Str("attestation", string(data)).Msg("Submitted attestation")
e.Str("attestations", string(data)).Msg("Submitted attestations")
}
}

View File

@ -27,7 +27,7 @@ import (
)
func TestService(t *testing.T) {
attestationSubmitter := mock.NewAttestationSubmitter()
attestationsSubmitter := mock.NewAttestationsSubmitter()
beaconBlockSubmitter := mock.NewBeaconBlockSubmitter()
beaconCommitteeSubscriptionSubmitter := mock.NewBeaconCommitteeSubscriptionsSubmitter()
aggregateAttestationSubmitter := mock.NewAggregateAttestationsSubmitter()
@ -38,20 +38,20 @@ func TestService(t *testing.T) {
err string
}{
{
name: "AttestationSubmitterMissing",
name: "AttestationsSubmitterMissing",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithBeaconBlockSubmitter(beaconBlockSubmitter),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(beaconCommitteeSubscriptionSubmitter),
immediate.WithAggregateAttestationsSubmitter(aggregateAttestationSubmitter),
},
err: "problem with parameters: no attestation submitter specified",
err: "problem with parameters: no attestations submitter specified",
},
{
name: "BeaconBlockSubmitterMissing",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(attestationSubmitter),
immediate.WithAttestationsSubmitter(attestationsSubmitter),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(beaconCommitteeSubscriptionSubmitter),
immediate.WithAggregateAttestationsSubmitter(aggregateAttestationSubmitter),
},
@ -61,7 +61,7 @@ func TestService(t *testing.T) {
name: "AttestationSubnetSubscriptionsSubmitterMissing",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(attestationSubmitter),
immediate.WithAttestationsSubmitter(attestationsSubmitter),
immediate.WithBeaconBlockSubmitter(beaconBlockSubmitter),
immediate.WithAggregateAttestationsSubmitter(aggregateAttestationSubmitter),
},
@ -71,7 +71,7 @@ func TestService(t *testing.T) {
name: "AggregateAttestationSubmitterMissing",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(attestationSubmitter),
immediate.WithAttestationsSubmitter(attestationsSubmitter),
immediate.WithBeaconBlockSubmitter(beaconBlockSubmitter),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(beaconCommitteeSubscriptionSubmitter),
},
@ -81,7 +81,7 @@ func TestService(t *testing.T) {
name: "Good",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.TraceLevel),
immediate.WithAttestationSubmitter(attestationSubmitter),
immediate.WithAttestationsSubmitter(attestationsSubmitter),
immediate.WithBeaconBlockSubmitter(beaconBlockSubmitter),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(beaconCommitteeSubscriptionSubmitter),
immediate.WithAggregateAttestationsSubmitter(aggregateAttestationSubmitter),
@ -103,14 +103,14 @@ func TestService(t *testing.T) {
func TestInterfaces(t *testing.T) {
s, err := immediate.New(context.Background(),
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
)
require.NoError(t, err)
require.Implements(t, (*submitter.BeaconBlockSubmitter)(nil), s)
require.Implements(t, (*submitter.AttestationSubmitter)(nil), s)
require.Implements(t, (*submitter.AttestationsSubmitter)(nil), s)
require.Implements(t, (*submitter.BeaconCommitteeSubscriptionsSubmitter)(nil), s)
require.Implements(t, (*submitter.AggregateAttestationsSubmitter)(nil), s)
}
@ -126,7 +126,7 @@ func TestSubmitBeaconBlock(t *testing.T) {
name: "Nil",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -137,7 +137,7 @@ func TestSubmitBeaconBlock(t *testing.T) {
name: "Empty",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -148,7 +148,7 @@ func TestSubmitBeaconBlock(t *testing.T) {
name: "Erroring",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewErroringBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -160,7 +160,7 @@ func TestSubmitBeaconBlock(t *testing.T) {
name: "Good",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.TraceLevel),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -184,57 +184,58 @@ func TestSubmitBeaconBlock(t *testing.T) {
}
}
func TestSubmitAttestation(t *testing.T) {
func TestSubmitAttestations(t *testing.T) {
tests := []struct {
name string
params []immediate.Parameter
attestation *spec.Attestation
err string
name string
params []immediate.Parameter
attestations []*spec.Attestation
err string
}{
{
name: "Nil",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
},
err: "no attestation supplied",
err: "no attestations supplied",
},
{
name: "Empty",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
},
attestation: &spec.Attestation{},
attestations: []*spec.Attestation{},
err: "no attestations supplied",
},
{
name: "Erroring",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewErroringAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewErroringAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
},
attestation: &spec.Attestation{},
err: "failed to submit attestation: error",
attestations: []*spec.Attestation{{}},
err: "failed to submit attestations: error",
},
{
name: "Good",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.TraceLevel),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
},
attestation: &spec.Attestation{},
attestations: []*spec.Attestation{{}},
},
}
@ -243,7 +244,7 @@ func TestSubmitAttestation(t *testing.T) {
require.NoError(t, err)
t.Run(test.name, func(t *testing.T) {
err := s.SubmitAttestation(context.Background(), test.attestation)
err := s.SubmitAttestations(context.Background(), test.attestations)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
@ -264,7 +265,7 @@ func TestSubmitAggregateAttestations(t *testing.T) {
name: "Nil",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -275,7 +276,7 @@ func TestSubmitAggregateAttestations(t *testing.T) {
name: "Empty",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -287,7 +288,7 @@ func TestSubmitAggregateAttestations(t *testing.T) {
name: "Erroring",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewErroringAggregateAttestationsSubmitter()),
@ -301,7 +302,7 @@ func TestSubmitAggregateAttestations(t *testing.T) {
name: "Good",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.TraceLevel),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -338,7 +339,7 @@ func TestSubmitBeaconCommitteeSubscriptions(t *testing.T) {
name: "Nil",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -349,7 +350,7 @@ func TestSubmitBeaconCommitteeSubscriptions(t *testing.T) {
name: "Empty",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -361,7 +362,7 @@ func TestSubmitBeaconCommitteeSubscriptions(t *testing.T) {
name: "Erroring",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.Disabled),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewErroringBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),
@ -375,7 +376,7 @@ func TestSubmitBeaconCommitteeSubscriptions(t *testing.T) {
name: "Good",
params: []immediate.Parameter{
immediate.WithLogLevel(zerolog.TraceLevel),
immediate.WithAttestationSubmitter(mock.NewAttestationSubmitter()),
immediate.WithAttestationsSubmitter(mock.NewAttestationsSubmitter()),
immediate.WithBeaconBlockSubmitter(mock.NewBeaconBlockSubmitter()),
immediate.WithBeaconCommitteeSubscriptionsSubmitter(mock.NewBeaconCommitteeSubscriptionsSubmitter()),
immediate.WithAggregateAttestationsSubmitter(mock.NewAggregateAttestationsSubmitter()),

View File

@ -0,0 +1,45 @@
// Copyright © 2020 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package multinode
import (
"context"
"strings"
eth2client "github.com/attestantio/go-eth2-client"
)
// serviceInfo returns the service name and provider information.
func (s *Service) serviceInfo(ctx context.Context, submitter interface{}) (string, string) {
serviceName := "<unknown>"
provider := "<unknown>"
if service, isService := submitter.(eth2client.Service); isService {
provider = service.Address()
}
if service, isService := submitter.(eth2client.NodeVersionProvider); isService {
nodeVersion, err := service.NodeVersion(ctx)
if err == nil {
switch {
case strings.Contains(strings.ToLower(nodeVersion), "lighthouse"):
serviceName = "lighthouse"
case strings.Contains(strings.ToLower(nodeVersion), "prysm"):
serviceName = "prysm"
case strings.Contains(strings.ToLower(nodeVersion), "teku"):
serviceName = "teku"
}
}
}
return serviceName, provider
}

View File

@ -30,7 +30,7 @@ type parameters struct {
clientMonitor metrics.ClientMonitor
processConcurrency int64
beaconBlockSubmitters map[string]eth2client.BeaconBlockSubmitter
attestationSubmitters map[string]eth2client.AttestationSubmitter
attestationsSubmitters map[string]eth2client.AttestationsSubmitter
aggregateAttestationsSubmitters map[string]eth2client.AggregateAttestationsSubmitter
beaconCommitteeSubscriptionsSubmitters map[string]eth2client.BeaconCommitteeSubscriptionsSubmitter
}
@ -74,10 +74,10 @@ func WithBeaconBlockSubmitters(submitters map[string]eth2client.BeaconBlockSubmi
})
}
// WithAttestationSubmitters sets the attestation submitters.
func WithAttestationSubmitters(submitters map[string]eth2client.AttestationSubmitter) Parameter {
// WithAttestationsSubmitters sets the attestation submitters.
func WithAttestationsSubmitters(submitters map[string]eth2client.AttestationsSubmitter) Parameter {
return parameterFunc(func(p *parameters) {
p.attestationSubmitters = submitters
p.attestationsSubmitters = submitters
})
}
@ -116,8 +116,8 @@ func parseAndCheckParameters(params ...Parameter) (*parameters, error) {
if len(parameters.beaconBlockSubmitters) == 0 {
return nil, errors.New("no beacon block submitters specified")
}
if len(parameters.attestationSubmitters) == 0 {
return nil, errors.New("no attestation submitters specified")
if len(parameters.attestationsSubmitters) == 0 {
return nil, errors.New("no attestations submitters specified")
}
if len(parameters.aggregateAttestationsSubmitters) == 0 {
return nil, errors.New("no aggregate attestations submitters specified")

View File

@ -28,7 +28,7 @@ type Service struct {
clientMonitor metrics.ClientMonitor
processConcurrency int64
beaconBlockSubmitters map[string]eth2client.BeaconBlockSubmitter
attestationSubmitters map[string]eth2client.AttestationSubmitter
attestationsSubmitters map[string]eth2client.AttestationsSubmitter
aggregateAttestationsSubmitters map[string]eth2client.AggregateAttestationsSubmitter
beaconCommitteeSubscriptionSubmitters map[string]eth2client.BeaconCommitteeSubscriptionsSubmitter
}
@ -53,7 +53,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) {
clientMonitor: parameters.clientMonitor,
processConcurrency: parameters.processConcurrency,
beaconBlockSubmitters: parameters.beaconBlockSubmitters,
attestationSubmitters: parameters.attestationSubmitters,
attestationsSubmitters: parameters.attestationsSubmitters,
aggregateAttestationsSubmitters: parameters.aggregateAttestationsSubmitters,
beaconCommitteeSubscriptionSubmitters: parameters.beaconCommitteeSubscriptionsSubmitters,
}

View File

@ -26,24 +26,24 @@ import (
"golang.org/x/sync/semaphore"
)
// SubmitAttestation submits an attestation.
func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attestation) error {
if attestation == nil {
return errors.New("no attestation supplied")
// SubmitAttestations submits a batch of attestations.
func (s *Service) SubmitAttestations(ctx context.Context, attestations []*spec.Attestation) error {
if len(attestations) == 0 {
return errors.New("no attestations supplied")
}
sem := semaphore.NewWeighted(s.processConcurrency)
var wg sync.WaitGroup
for name, submitter := range s.attestationSubmitters {
for name, submitter := range s.attestationsSubmitters {
wg.Add(1)
go func(ctx context.Context,
sem *semaphore.Weighted,
wg *sync.WaitGroup,
name string,
submitter eth2client.AttestationSubmitter,
submitter eth2client.AttestationsSubmitter,
) {
defer wg.Done()
log := log.With().Str("beacon_node_address", name).Uint64("slot", uint64(attestation.Data.Slot)).Logger()
log := log.With().Str("beacon_node_address", name).Uint64("slot", uint64(attestations[0].Data.Slot)).Logger()
if err := sem.Acquire(ctx, 1); err != nil {
log.Error().Err(err).Msg("Failed to acquire semaphore")
return
@ -52,8 +52,8 @@ func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attes
serverType, address := s.serviceInfo(ctx, submitter)
started := time.Now()
err := submitter.SubmitAttestation(ctx, attestation)
s.clientMonitor.ClientOperation(address, "submit attestation", err == nil, time.Since(started))
err := submitter.SubmitAttestations(ctx, attestations)
s.clientMonitor.ClientOperation(address, "submit attestations", err == nil, time.Since(started))
if err != nil {
switch {
case serverType == "lighthouse" && strings.Contains(err.Error(), "PriorAttestationKnown"):
@ -64,47 +64,22 @@ func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attes
// Lighthouse rejects an attestation for a block that is not its current head. It is possible
// that the node is just behind, and we can't do anything about it anyway at this point having
// already signed an attestation for this slot, so ignore the error.
log.Trace().Msg("Node does not know head slot; ignored")
log.Debug().Err(err).Msg("Node does not know head block; rejected")
case serverType == "lighthouse" && strings.Contains(err.Error(), "InvalidSignature"):
data, err2 := json.Marshal(attestations)
if err2 != nil {
log.Error().Err(err).Msg("Failed to marshal JSON")
}
log.Warn().Err(err).Str("data", string(data)).Msg("Invalid signature!")
default:
log.Warn().Err(err).Msg("Failed to submit attestation")
return
}
} else {
log.Trace().Msg("Submitted attestations")
}
log.Trace().Msg("Submitted attestation")
}(ctx, sem, &wg, name, submitter)
}
wg.Wait()
if e := log.Trace(); e.Enabled() {
data, err := json.Marshal(attestation)
if err == nil {
e.Str("attestation", string(data)).Msg("Submitted attestation")
}
}
return nil
}
// serviceInfo returns the service name and provider information.
func (s *Service) serviceInfo(ctx context.Context, submitter interface{}) (string, string) {
serviceName := "<unknown>"
provider := "<unknown>"
if service, isService := submitter.(eth2client.Service); isService {
provider = service.Address()
}
if service, isService := submitter.(eth2client.NodeVersionProvider); isService {
nodeVersion, err := service.NodeVersion(ctx)
if err == nil {
switch {
case strings.Contains(strings.ToLower(nodeVersion), "lighthouse"):
serviceName = "lighthouse"
case strings.Contains(strings.ToLower(nodeVersion), "prysm"):
serviceName = "prysm"
case strings.Contains(strings.ToLower(nodeVersion), "teku"):
serviceName = "teku"
}
}
}
return serviceName, provider
}

View File

@ -64,16 +64,16 @@ func (s *Service) SubmitBeaconBlock(ctx context.Context, block *spec.SignedBeaco
return nil
}
// SubmitAttestation submits a beacon block attestation.
func (s *Service) SubmitAttestation(ctx context.Context, attestation *spec.Attestation) error {
if attestation == nil {
return errors.New("no attestation supplied")
// SubmitAttestations submits multiple attestations.
func (s *Service) SubmitAttestations(ctx context.Context, attestations []*spec.Attestation) error {
if len(attestations) == 0 {
return errors.New("no attestations supplied")
}
if e := log.Trace(); e.Enabled() {
data, err := json.Marshal(attestation)
data, err := json.Marshal(attestations)
if err == nil {
e.Str("attestation", string(data)).Msg("Not submitting attestation")
e.Str("attestations", string(data)).Msg("Not submitting attestations")
}
}

View File

@ -51,7 +51,7 @@ func TestSubmit(t *testing.T) {
require.NoError(t, err)
require.EqualError(t, s.SubmitBeaconBlock(context.Background(), nil), "no beacon block supplied")
require.EqualError(t, s.SubmitAttestation(context.Background(), nil), "no attestation supplied")
require.EqualError(t, s.SubmitAttestations(context.Background(), nil), "no attestations supplied")
require.EqualError(t, s.SubmitBeaconCommitteeSubscriptions(context.Background(), nil), "no subscriptions supplied")
require.EqualError(t, s.SubmitAggregateAttestations(context.Background(), nil), "no aggregate attestations supplied")
}
@ -62,7 +62,7 @@ func TestInterfaces(t *testing.T) {
)
require.NoError(t, err)
require.Implements(t, (*submitter.BeaconBlockSubmitter)(nil), s)
require.Implements(t, (*submitter.AttestationSubmitter)(nil), s)
require.Implements(t, (*submitter.AttestationsSubmitter)(nil), s)
require.Implements(t, (*submitter.BeaconCommitteeSubscriptionsSubmitter)(nil), s)
require.Implements(t, (*submitter.AggregateAttestationsSubmitter)(nil), s)
}

View File

@ -23,10 +23,10 @@ import (
// Service is the submitter service.
type Service interface{}
// AttestationSubmitter is the interface for a submitter of attestations.
type AttestationSubmitter interface {
// SubmitAttestation submits an attestation.
SubmitAttestation(ctx context.Context, block *spec.Attestation) error
// AttestationsSubmitter is the interface for a submitter of attestations.
type AttestationsSubmitter interface {
// SubmitAttestations submits multiple attestations.
SubmitAttestations(ctx context.Context, attestations []*spec.Attestation) error
}
// BeaconBlockSubmitter is the interface for a submitter of beacon blocks.