EIP-7549: validator client (#14158)

* EIP-7549: validator client

* server code

* tests

* build fix

* review

* remove context

* Revert "Auxiliary commit to revert individual files from 16fed79a1ae0bbe4a08cb9819c2785d6e34958dd"

This reverts commit f59e1459f3f7561e0483bc8542110794951585c5.
This commit is contained in:
Radosław Kapka
2024-07-11 20:41:09 +02:00
committed by GitHub
parent 7c81c7da90
commit 365c6252ba
30 changed files with 1460 additions and 570 deletions

View File

@@ -16,6 +16,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/network/httputil"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"go.opencensus.io/trace"
@@ -79,52 +80,84 @@ func (v *validator) SubmitAggregateAndProof(ctx context.Context, slot primitives
// https://github.com/ethereum/consensus-specs/blob/v0.9.3/specs/validator/0_beacon-chain-validator.md#broadcast-aggregate
v.waitToSlotTwoThirds(ctx, slot)
res, err := v.validatorClient.SubmitAggregateSelectionProof(ctx, &ethpb.AggregateSelectionRequest{
postElectra := slots.ToEpoch(slot) >= params.BeaconConfig().ElectraForkEpoch
aggSelectionRequest := &ethpb.AggregateSelectionRequest{
Slot: slot,
CommitteeIndex: duty.CommitteeIndex,
PublicKey: pubKey[:],
SlotSignature: slotSig,
}, duty.ValidatorIndex, uint64(len(duty.Committee)))
if err != nil {
// handle grpc not found
s, ok := status.FromError(err)
grpcNotFound := ok && s.Code() == codes.NotFound
// handle http not found
jsonErr := &httputil.DefaultJsonError{}
httpNotFound := errors.As(err, &jsonErr) && jsonErr.Code == http.StatusNotFound
if grpcNotFound || httpNotFound {
log.WithField("slot", slot).WithError(err).Warn("No attestations to aggregate")
} else {
log.WithField("slot", slot).WithError(err).Error("Could not submit aggregate selection proof to beacon node")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
}
}
var agg ethpb.AggregateAttAndProof
if postElectra {
res, err := v.validatorClient.SubmitAggregateSelectionProofElectra(ctx, aggSelectionRequest, duty.ValidatorIndex, uint64(len(duty.Committee)))
if err != nil {
v.handleSubmitAggSelectionProofError(err, slot, fmtKey)
return
}
return
agg = res.AggregateAndProof
} else {
res, err := v.validatorClient.SubmitAggregateSelectionProof(ctx, aggSelectionRequest, duty.ValidatorIndex, uint64(len(duty.Committee)))
if err != nil {
v.handleSubmitAggSelectionProofError(err, slot, fmtKey)
return
}
agg = res.AggregateAndProof
}
sig, err := v.aggregateAndProofSig(ctx, pubKey, res.AggregateAndProof, slot)
sig, err := v.aggregateAndProofSig(ctx, pubKey, agg, slot)
if err != nil {
log.WithError(err).Error("Could not sign aggregate and proof")
return
}
_, err = v.validatorClient.SubmitSignedAggregateSelectionProof(ctx, &ethpb.SignedAggregateSubmitRequest{
SignedAggregateAndProof: &ethpb.SignedAggregateAttestationAndProof{
Message: res.AggregateAndProof,
Signature: sig,
},
})
if err != nil {
log.WithError(err).Error("Could not submit signed aggregate and proof to beacon node")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
if postElectra {
msg, ok := agg.(*ethpb.AggregateAttestationAndProofElectra)
if !ok {
log.Errorf("Message is not %T", &ethpb.AggregateAttestationAndProofElectra{})
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
}
return
}
_, err = v.validatorClient.SubmitSignedAggregateSelectionProofElectra(ctx, &ethpb.SignedAggregateSubmitElectraRequest{
SignedAggregateAndProof: &ethpb.SignedAggregateAttestationAndProofElectra{
Message: msg,
Signature: sig,
},
})
if err != nil {
log.WithError(err).Error("Could not submit signed aggregate and proof to beacon node")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
}
return
}
} else {
msg, ok := agg.(*ethpb.AggregateAttestationAndProof)
if !ok {
log.Errorf("Message is not %T", &ethpb.AggregateAttestationAndProof{})
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
}
return
}
_, err = v.validatorClient.SubmitSignedAggregateSelectionProof(ctx, &ethpb.SignedAggregateSubmitRequest{
SignedAggregateAndProof: &ethpb.SignedAggregateAttestationAndProof{
Message: msg,
Signature: sig,
},
})
if err != nil {
log.WithError(err).Error("Could not submit signed aggregate and proof to beacon node")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
}
return
}
return
}
if err := v.saveSubmittedAtt(res.AggregateAndProof.Aggregate.Data, pubKey[:], true); err != nil {
if err := v.saveSubmittedAtt(agg.AggregateVal().GetData(), pubKey[:], true); err != nil {
log.WithError(err).Error("Could not add aggregator indices to logs")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(fmtKey).Inc()
@@ -196,29 +229,61 @@ func (v *validator) waitToSlotTwoThirds(ctx context.Context, slot primitives.Slo
// This returns the signature of validator signing over aggregate and
// proof object.
func (v *validator) aggregateAndProofSig(ctx context.Context, pubKey [fieldparams.BLSPubkeyLength]byte, agg *ethpb.AggregateAttestationAndProof, slot primitives.Slot) ([]byte, error) {
func (v *validator) aggregateAndProofSig(ctx context.Context, pubKey [fieldparams.BLSPubkeyLength]byte, agg ethpb.AggregateAttAndProof, slot primitives.Slot) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "validator.aggregateAndProofSig")
defer span.End()
d, err := v.domainData(ctx, slots.ToEpoch(agg.Aggregate.Data.Slot), params.BeaconConfig().DomainAggregateAndProof[:])
d, err := v.domainData(ctx, slots.ToEpoch(agg.AggregateVal().GetData().Slot), params.BeaconConfig().DomainAggregateAndProof[:])
if err != nil {
return nil, err
}
var sig bls.Signature
root, err := signing.ComputeSigningRoot(agg, d.SignatureDomain)
if err != nil {
return nil, err
}
sig, err = v.km.Sign(ctx, &validatorpb.SignRequest{
signRequest := &validatorpb.SignRequest{
PublicKey: pubKey[:],
SigningRoot: root[:],
SignatureDomain: d.SignatureDomain,
Object: &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: agg},
SigningSlot: slot,
})
}
if agg.Version() >= version.Electra {
aggregate, ok := agg.(*ethpb.AggregateAttestationAndProofElectra)
if !ok {
return nil, fmt.Errorf("wrong aggregate type (expected %T, got %T)", &ethpb.AggregateAttestationAndProofElectra{}, agg)
}
signRequest.Object = &validatorpb.SignRequest_AggregateAttestationAndProofElectra{AggregateAttestationAndProofElectra: aggregate}
} else {
aggregate, ok := agg.(*ethpb.AggregateAttestationAndProof)
if !ok {
return nil, fmt.Errorf("wrong aggregate type (expected %T, got %T)", &ethpb.AggregateAttestationAndProof{}, agg)
}
signRequest.Object = &validatorpb.SignRequest_AggregateAttestationAndProof{AggregateAttestationAndProof: aggregate}
}
sig, err := v.km.Sign(ctx, signRequest)
if err != nil {
return nil, err
}
return sig.Marshal(), nil
}
func (v *validator) handleSubmitAggSelectionProofError(err error, slot primitives.Slot, hexPubkey string) {
// handle grpc not found
s, ok := status.FromError(err)
grpcNotFound := ok && s.Code() == codes.NotFound
// handle http not found
jsonErr := &httputil.DefaultJsonError{}
httpNotFound := errors.As(err, &jsonErr) && jsonErr.Code == http.StatusNotFound
if grpcNotFound || httpNotFound {
log.WithField("slot", slot).WithError(err).Warn("No attestations to aggregate")
} else {
log.WithField("slot", slot).WithError(err).Error("Could not submit aggregate selection proof to beacon node")
if v.emitAccountMetrics {
ValidatorAggFailVec.WithLabelValues(hexPubkey).Inc()
}
}
}

View File

@@ -86,7 +86,7 @@ func TestSubmitAggregateAndProof_SignFails(t *testing.T) {
func TestSubmitAggregateAndProof_Ok(t *testing.T) {
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("SlashingProtectionMinimal:%v", isSlashingProtectionMinimal), func(t *testing.T) {
t.Run(fmt.Sprintf("Phase 0 (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
var pubKey [fieldparams.BLSPubkeyLength]byte
@@ -132,6 +132,59 @@ func TestSubmitAggregateAndProof_Ok(t *testing.T) {
validator.SubmitAggregateAndProof(context.Background(), 0, pubKey)
})
}
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("Electra (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
electraForkEpoch := uint64(1)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.ElectraForkEpoch = primitives.Epoch(electraForkEpoch)
params.OverrideBeaconConfig(cfg)
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
var pubKey [fieldparams.BLSPubkeyLength]byte
copy(pubKey[:], validatorKey.PublicKey().Marshal())
validator.duties = &ethpb.DutiesResponse{
CurrentEpochDuties: []*ethpb.DutiesResponse_Duty{
{
PublicKey: validatorKey.PublicKey().Marshal(),
},
},
}
m.validatorClient.EXPECT().DomainData(
gomock.Any(), // ctx
gomock.Any(), // epoch
).Return(&ethpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
m.validatorClient.EXPECT().SubmitAggregateSelectionProofElectra(
gomock.Any(), // ctx
gomock.AssignableToTypeOf(&ethpb.AggregateSelectionRequest{}),
gomock.Any(),
gomock.Any(),
).Return(&ethpb.AggregateSelectionElectraResponse{
AggregateAndProof: &ethpb.AggregateAttestationAndProofElectra{
AggregatorIndex: 0,
Aggregate: util.HydrateAttestationElectra(&ethpb.AttestationElectra{
AggregationBits: make([]byte, 1),
}),
SelectionProof: make([]byte, 96),
},
}, nil)
m.validatorClient.EXPECT().DomainData(
gomock.Any(), // ctx
gomock.Any(), // epoch
).Return(&ethpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
m.validatorClient.EXPECT().SubmitSignedAggregateSelectionProofElectra(
gomock.Any(), // ctx
gomock.AssignableToTypeOf(&ethpb.SignedAggregateSubmitElectraRequest{}),
).Return(&ethpb.SignedAggregateSubmitResponse{AttestationDataRoot: make([]byte, 32)}, nil)
validator.SubmitAggregateAndProof(context.Background(), params.BeaconConfig().SlotsPerEpoch.Mul(electraForkEpoch), pubKey)
})
}
}
func TestSubmitAggregateAndProof_Distributed(t *testing.T) {
@@ -236,7 +289,7 @@ func TestWaitForSlotTwoThird_DoneContext_ReturnsImmediately(t *testing.T) {
func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) {
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("SlashingProtectionMinimal:%v", isSlashingProtectionMinimal), func(t *testing.T) {
t.Run(fmt.Sprintf("Phase 0 (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
@@ -260,4 +313,35 @@ func TestAggregateAndProofSignature_CanSignValidSignature(t *testing.T) {
require.NoError(t, err)
})
}
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("Electra (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
electraForkEpoch := uint64(1)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.ElectraForkEpoch = primitives.Epoch(electraForkEpoch)
params.OverrideBeaconConfig(cfg)
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
var pubKey [fieldparams.BLSPubkeyLength]byte
copy(pubKey[:], validatorKey.PublicKey().Marshal())
m.validatorClient.EXPECT().DomainData(
gomock.Any(), // ctx
&ethpb.DomainRequest{Epoch: 0, Domain: params.BeaconConfig().DomainAggregateAndProof[:]},
).Return(&ethpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
agg := &ethpb.AggregateAttestationAndProofElectra{
AggregatorIndex: 0,
Aggregate: util.HydrateAttestationElectra(&ethpb.AttestationElectra{
AggregationBits: bitfield.NewBitlist(1),
}),
SelectionProof: make([]byte, 96),
}
sig, err := validator.aggregateAndProofSig(context.Background(), pubKey, agg, params.BeaconConfig().SlotsPerEpoch.Mul(electraForkEpoch) /* slot */)
require.NoError(t, err)
_, err = bls.SignatureFromBytes(sig)
require.NoError(t, err)
})
}
}

View File

@@ -85,14 +85,9 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
return
}
indexedAtt := &ethpb.IndexedAttestation{
AttestingIndices: []uint64{uint64(duty.ValidatorIndex)},
Data: data,
}
_, signingRoot, err := v.domainAndSigningRoot(ctx, indexedAtt.Data)
sig, _, err := v.signAtt(ctx, pubKey, data, slot)
if err != nil {
log.WithError(err).Error("Could not get domain and signing root from attestation")
log.WithError(err).Error("Could not sign attestation")
if v.emitAccountMetrics {
ValidatorAttestFailVec.WithLabelValues(fmtKey).Inc()
}
@@ -100,9 +95,26 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
return
}
sig, _, err := v.signAtt(ctx, pubKey, data, slot)
postElectra := slots.ToEpoch(slot) >= params.BeaconConfig().ElectraForkEpoch
var indexedAtt ethpb.IndexedAtt
if postElectra {
indexedAtt = &ethpb.IndexedAttestationElectra{
AttestingIndices: []uint64{uint64(duty.ValidatorIndex)},
Data: data,
Signature: sig,
}
} else {
indexedAtt = &ethpb.IndexedAttestation{
AttestingIndices: []uint64{uint64(duty.ValidatorIndex)},
Data: data,
Signature: sig,
}
}
_, signingRoot, err := v.domainAndSigningRoot(ctx, indexedAtt.GetData())
if err != nil {
log.WithError(err).Error("Could not sign attestation")
log.WithError(err).Error("Could not get domain and signing root from attestation")
if v.emitAccountMetrics {
ValidatorAttestFailVec.WithLabelValues(fmtKey).Inc()
}
@@ -127,25 +139,42 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
return
}
aggregationBitfield := bitfield.NewBitlist(uint64(len(duty.Committee)))
aggregationBitfield.SetBitAt(indexInCommittee, true)
attestation := &ethpb.Attestation{
Data: data,
AggregationBits: aggregationBitfield,
Signature: sig,
// TODO: Extend to Electra
phase0Att, ok := indexedAtt.(*ethpb.IndexedAttestation)
if ok {
// Send the attestation to the beacon node.
if err := v.db.SlashableAttestationCheck(ctx, phase0Att, pubKey, signingRoot, v.emitAccountMetrics, ValidatorAttestFailVec); err != nil {
log.WithError(err).Error("Failed attestation slashing protection check")
log.WithFields(
attestationLogFields(pubKey, indexedAtt),
).Debug("Attempted slashable attestation details")
tracing.AnnotateError(span, err)
return
}
}
// Set the signature of the attestation and send it out to the beacon node.
indexedAtt.Signature = sig
if err := v.db.SlashableAttestationCheck(ctx, indexedAtt, pubKey, signingRoot, v.emitAccountMetrics, ValidatorAttestFailVec); err != nil {
log.WithError(err).Error("Failed attestation slashing protection check")
log.WithFields(
attestationLogFields(pubKey, indexedAtt),
).Debug("Attempted slashable attestation details")
tracing.AnnotateError(span, err)
return
aggregationBitfield := bitfield.NewBitlist(uint64(len(duty.Committee)))
aggregationBitfield.SetBitAt(indexInCommittee, true)
committeeBits := primitives.NewAttestationCommitteeBits()
var attResp *ethpb.AttestResponse
if postElectra {
attestation := &ethpb.AttestationElectra{
Data: data,
AggregationBits: aggregationBitfield,
CommitteeBits: committeeBits,
Signature: sig,
}
attestation.CommitteeBits.SetBitAt(uint64(req.CommitteeIndex), true)
attResp, err = v.validatorClient.ProposeAttestationElectra(ctx, attestation)
} else {
attestation := &ethpb.Attestation{
Data: data,
AggregationBits: aggregationBitfield,
Signature: sig,
}
attResp, err = v.validatorClient.ProposeAttestation(ctx, attestation)
}
attResp, err := v.validatorClient.ProposeAttestation(ctx, attestation)
if err != nil {
log.WithError(err).Error("Could not submit attestation to beacon node")
if v.emitAccountMetrics {
@@ -167,12 +196,16 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
span.AddAttributes(
trace.Int64Attribute("slot", int64(slot)), // lint:ignore uintcast -- This conversion is OK for tracing.
trace.StringAttribute("attestationHash", fmt.Sprintf("%#x", attResp.AttestationDataRoot)),
trace.Int64Attribute("committeeIndex", int64(data.CommitteeIndex)),
trace.StringAttribute("blockRoot", fmt.Sprintf("%#x", data.BeaconBlockRoot)),
trace.Int64Attribute("justifiedEpoch", int64(data.Source.Epoch)),
trace.Int64Attribute("targetEpoch", int64(data.Target.Epoch)),
trace.StringAttribute("bitfield", fmt.Sprintf("%#x", aggregationBitfield)),
trace.StringAttribute("aggregationBitfield", fmt.Sprintf("%#x", aggregationBitfield)),
)
if postElectra {
span.AddAttributes(trace.StringAttribute("committeeBitfield", fmt.Sprintf("%#x", committeeBits)))
} else {
span.AddAttributes(trace.Int64Attribute("committeeIndex", int64(data.CommitteeIndex)))
}
if v.emitAccountMetrics {
ValidatorAttestSuccessVec.WithLabelValues(fmtKey).Inc()
@@ -296,16 +329,16 @@ func (v *validator) waitOneThirdOrValidBlock(ctx context.Context, slot primitive
}
}
func attestationLogFields(pubKey [fieldparams.BLSPubkeyLength]byte, indexedAtt *ethpb.IndexedAttestation) logrus.Fields {
func attestationLogFields(pubKey [fieldparams.BLSPubkeyLength]byte, indexedAtt ethpb.IndexedAtt) logrus.Fields {
return logrus.Fields{
"pubkey": fmt.Sprintf("%#x", pubKey),
"slot": indexedAtt.Data.Slot,
"committeeIndex": indexedAtt.Data.CommitteeIndex,
"blockRoot": fmt.Sprintf("%#x", indexedAtt.Data.BeaconBlockRoot),
"sourceEpoch": indexedAtt.Data.Source.Epoch,
"sourceRoot": fmt.Sprintf("%#x", indexedAtt.Data.Source.Root),
"targetEpoch": indexedAtt.Data.Target.Epoch,
"targetRoot": fmt.Sprintf("%#x", indexedAtt.Data.Target.Root),
"signature": fmt.Sprintf("%#x", indexedAtt.Signature),
"slot": indexedAtt.GetData().Slot,
"committeeIndex": indexedAtt.GetData().CommitteeIndex,
"blockRoot": fmt.Sprintf("%#x", indexedAtt.GetData().BeaconBlockRoot),
"sourceEpoch": indexedAtt.GetData().Source.Epoch,
"sourceRoot": fmt.Sprintf("%#x", indexedAtt.GetData().Source.Root),
"targetEpoch": indexedAtt.GetData().Target.Epoch,
"targetRoot": fmt.Sprintf("%#x", indexedAtt.GetData().Target.Root),
"signature": fmt.Sprintf("%#x", indexedAtt.GetSignature()),
}
}

View File

@@ -108,7 +108,7 @@ func TestAttestToBlockHead_SubmitAttestation_RequestFailure(t *testing.T) {
func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) {
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("SlashingProtectionMinimal:%v", isSlashingProtectionMinimal), func(t *testing.T) {
t.Run(fmt.Sprintf("Phase 0 (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
hook := logTest.NewGlobal()
@@ -167,6 +167,89 @@ func TestAttestToBlockHead_AttestsCorrectly(t *testing.T) {
root, err := signing.ComputeSigningRoot(expectedAttestation.Data, make([]byte, 32))
require.NoError(t, err)
sig, err := validator.km.Sign(context.Background(), &validatorpb.SignRequest{
PublicKey: validatorKey.PublicKey().Marshal(),
SigningRoot: root[:],
})
require.NoError(t, err)
expectedAttestation.Signature = sig.Marshal()
if !reflect.DeepEqual(generatedAttestation, expectedAttestation) {
t.Errorf("Incorrectly attested head, wanted %v, received %v", expectedAttestation, generatedAttestation)
diff, _ := messagediff.PrettyDiff(expectedAttestation, generatedAttestation)
t.Log(diff)
}
require.LogsDoNotContain(t, hook, "Could not")
})
}
for _, isSlashingProtectionMinimal := range [...]bool{false, true} {
t.Run(fmt.Sprintf("Electra (SlashingProtectionMinimal:%v)", isSlashingProtectionMinimal), func(t *testing.T) {
electraForkEpoch := uint64(1)
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()
cfg.ElectraForkEpoch = primitives.Epoch(electraForkEpoch)
params.OverrideBeaconConfig(cfg)
validator, m, validatorKey, finish := setup(t, isSlashingProtectionMinimal)
defer finish()
hook := logTest.NewGlobal()
validatorIndex := primitives.ValidatorIndex(7)
committee := []primitives.ValidatorIndex{0, 3, 4, 2, validatorIndex, 6, 8, 9, 10}
var pubKey [fieldparams.BLSPubkeyLength]byte
copy(pubKey[:], validatorKey.PublicKey().Marshal())
validator.duties = &ethpb.DutiesResponse{CurrentEpochDuties: []*ethpb.DutiesResponse_Duty{
{
PublicKey: validatorKey.PublicKey().Marshal(),
CommitteeIndex: 5,
Committee: committee,
ValidatorIndex: validatorIndex,
},
}}
beaconBlockRoot := bytesutil.ToBytes32([]byte("A"))
targetRoot := bytesutil.ToBytes32([]byte("B"))
sourceRoot := bytesutil.ToBytes32([]byte("C"))
m.validatorClient.EXPECT().AttestationData(
gomock.Any(), // ctx
gomock.AssignableToTypeOf(&ethpb.AttestationDataRequest{}),
).Return(&ethpb.AttestationData{
BeaconBlockRoot: beaconBlockRoot[:],
Target: &ethpb.Checkpoint{Root: targetRoot[:]},
Source: &ethpb.Checkpoint{Root: sourceRoot[:], Epoch: 3},
}, nil)
m.validatorClient.EXPECT().DomainData(
gomock.Any(), // ctx
gomock.Any(), // epoch
).Times(2).Return(&ethpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
var generatedAttestation *ethpb.AttestationElectra
m.validatorClient.EXPECT().ProposeAttestationElectra(
gomock.Any(), // ctx
gomock.AssignableToTypeOf(&ethpb.AttestationElectra{}),
).Do(func(_ context.Context, att *ethpb.AttestationElectra) {
generatedAttestation = att
}).Return(&ethpb.AttestResponse{}, nil /* error */)
validator.SubmitAttestation(context.Background(), params.BeaconConfig().SlotsPerEpoch.Mul(electraForkEpoch), pubKey)
aggregationBitfield := bitfield.NewBitlist(uint64(len(committee)))
aggregationBitfield.SetBitAt(4, true)
committeeBits := primitives.NewAttestationCommitteeBits()
committeeBits.SetBitAt(5, true)
expectedAttestation := &ethpb.AttestationElectra{
Data: &ethpb.AttestationData{
BeaconBlockRoot: beaconBlockRoot[:],
Target: &ethpb.Checkpoint{Root: targetRoot[:]},
Source: &ethpb.Checkpoint{Root: sourceRoot[:], Epoch: 3},
},
AggregationBits: aggregationBitfield,
CommitteeBits: committeeBits,
Signature: make([]byte, 96),
}
root, err := signing.ComputeSigningRoot(expectedAttestation.Data, make([]byte, 32))
require.NoError(t, err)
sig, err := validator.km.Sign(context.Background(), &validatorpb.SignRequest{
PublicKey: validatorKey.PublicKey().Marshal(),
SigningRoot: root[:],

View File

@@ -154,6 +154,10 @@ func (c *beaconApiValidatorClient) ProposeAttestation(ctx context.Context, in *e
})
}
func (c *beaconApiValidatorClient) ProposeAttestationElectra(ctx context.Context, in *ethpb.AttestationElectra) (*ethpb.AttestResponse, error) {
return nil, errors.New("ProposeAttestationElectra is not implemented")
}
func (c *beaconApiValidatorClient) ProposeBeaconBlock(ctx context.Context, in *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
ctx, span := trace.StartSpan(ctx, "beacon-api.ProposeBeaconBlock")
defer span.End()
@@ -185,6 +189,10 @@ func (c *beaconApiValidatorClient) SubmitAggregateSelectionProof(ctx context.Con
})
}
func (c *beaconApiValidatorClient) SubmitAggregateSelectionProofElectra(ctx context.Context, in *ethpb.AggregateSelectionRequest, index primitives.ValidatorIndex, committeeLength uint64) (*ethpb.AggregateSelectionElectraResponse, error) {
return nil, errors.New("SubmitAggregateSelectionProofElectra is not implemented")
}
func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProof(ctx context.Context, in *ethpb.SignedAggregateSubmitRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
ctx, span := trace.StartSpan(ctx, "beacon-api.SubmitSignedAggregateSelectionProof")
defer span.End()
@@ -194,6 +202,10 @@ func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProof(ctx conte
})
}
func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProofElectra(ctx context.Context, in *ethpb.SignedAggregateSubmitElectraRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
return nil, errors.New("SubmitSignedAggregateSelectionProofElectra is not implemented")
}
func (c *beaconApiValidatorClient) SubmitSignedContributionAndProof(ctx context.Context, in *ethpb.SignedContributionAndProof) (*empty.Empty, error) {
ctx, span := trace.StartSpan(ctx, "beacon-api.SubmitSignedContributionAndProof")
defer span.End()

View File

@@ -292,7 +292,7 @@ func TestGetValidatorCount(t *testing.T) {
}
chainClient := mock.NewMockChainClient(ctrl)
chainClient.EXPECT().ListValidators(
chainClient.EXPECT().Validators(
gomock.Any(),
gomock.Any(),
).Return(
@@ -300,7 +300,7 @@ func TestGetValidatorCount(t *testing.T) {
nil,
)
chainClient.EXPECT().GetChainHead(
chainClient.EXPECT().ChainHead(
gomock.Any(),
gomock.Any(),
).Return(

View File

@@ -71,6 +71,10 @@ func (c *grpcValidatorClient) ProposeAttestation(ctx context.Context, in *ethpb.
return c.beaconNodeValidatorClient.ProposeAttestation(ctx, in)
}
func (c *grpcValidatorClient) ProposeAttestationElectra(ctx context.Context, in *ethpb.AttestationElectra) (*ethpb.AttestResponse, error) {
return c.beaconNodeValidatorClient.ProposeAttestationElectra(ctx, in)
}
func (c *grpcValidatorClient) ProposeBeaconBlock(ctx context.Context, in *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
return c.beaconNodeValidatorClient.ProposeBeaconBlock(ctx, in)
}
@@ -87,10 +91,18 @@ func (c *grpcValidatorClient) SubmitAggregateSelectionProof(ctx context.Context,
return c.beaconNodeValidatorClient.SubmitAggregateSelectionProof(ctx, in)
}
func (c *grpcValidatorClient) SubmitAggregateSelectionProofElectra(ctx context.Context, in *ethpb.AggregateSelectionRequest, _ primitives.ValidatorIndex, _ uint64) (*ethpb.AggregateSelectionElectraResponse, error) {
return c.beaconNodeValidatorClient.SubmitAggregateSelectionProofElectra(ctx, in)
}
func (c *grpcValidatorClient) SubmitSignedAggregateSelectionProof(ctx context.Context, in *ethpb.SignedAggregateSubmitRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
return c.beaconNodeValidatorClient.SubmitSignedAggregateSelectionProof(ctx, in)
}
func (c *grpcValidatorClient) SubmitSignedAggregateSelectionProofElectra(ctx context.Context, in *ethpb.SignedAggregateSubmitElectraRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
return c.beaconNodeValidatorClient.SubmitSignedAggregateSelectionProofElectra(ctx, in)
}
func (c *grpcValidatorClient) SubmitSignedContributionAndProof(ctx context.Context, in *ethpb.SignedContributionAndProof) (*empty.Empty, error) {
return c.beaconNodeValidatorClient.SubmitSignedContributionAndProof(ctx, in)
}

View File

@@ -134,8 +134,11 @@ type ValidatorClient interface {
FeeRecipientByPubKey(ctx context.Context, in *ethpb.FeeRecipientByPubKeyRequest) (*ethpb.FeeRecipientByPubKeyResponse, error)
AttestationData(ctx context.Context, in *ethpb.AttestationDataRequest) (*ethpb.AttestationData, error)
ProposeAttestation(ctx context.Context, in *ethpb.Attestation) (*ethpb.AttestResponse, error)
ProposeAttestationElectra(ctx context.Context, in *ethpb.AttestationElectra) (*ethpb.AttestResponse, error)
SubmitAggregateSelectionProof(ctx context.Context, in *ethpb.AggregateSelectionRequest, index primitives.ValidatorIndex, committeeLength uint64) (*ethpb.AggregateSelectionResponse, error)
SubmitAggregateSelectionProofElectra(ctx context.Context, in *ethpb.AggregateSelectionRequest, _ primitives.ValidatorIndex, _ uint64) (*ethpb.AggregateSelectionElectraResponse, error)
SubmitSignedAggregateSelectionProof(ctx context.Context, in *ethpb.SignedAggregateSubmitRequest) (*ethpb.SignedAggregateSubmitResponse, error)
SubmitSignedAggregateSelectionProofElectra(ctx context.Context, in *ethpb.SignedAggregateSubmitElectraRequest) (*ethpb.SignedAggregateSubmitResponse, error)
ProposeExit(ctx context.Context, in *ethpb.SignedVoluntaryExit) (*ethpb.ProposeExitResponse, error)
SubscribeCommitteeSubnets(ctx context.Context, in *ethpb.CommitteeSubnetsSubscribeRequest, duties []*ethpb.DutiesResponse_Duty) (*empty.Empty, error)
CheckDoppelGanger(ctx context.Context, in *ethpb.DoppelGangerRequest) (*ethpb.DoppelGangerResponse, error)

View File

@@ -47,7 +47,7 @@ func TestValidator_HandleKeyReload(t *testing.T) {
PublicKeys: [][]byte{inactive.pub[:], active.pub[:]},
},
).Return(resp, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validator2.Status{validator2.Active},
@@ -83,7 +83,7 @@ func TestValidator_HandleKeyReload(t *testing.T) {
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(resp, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validator2.Status{validator2.Active},

View File

@@ -315,7 +315,7 @@ func TestCanonicalHeadSlot_FailedRPC(t *testing.T) {
chainClient: client,
genesisTime: 1,
}
client.EXPECT().GetChainHead(
client.EXPECT().ChainHead(
gomock.Any(),
gomock.Any(),
).Return(nil, errors.New("failed"))
@@ -330,7 +330,7 @@ func TestCanonicalHeadSlot_OK(t *testing.T) {
v := validator{
chainClient: client,
}
client.EXPECT().GetChainHead(
client.EXPECT().ChainHead(
gomock.Any(),
gomock.Any(),
).Return(&ethpb.ChainHead{HeadSlot: 0}, nil)
@@ -369,7 +369,7 @@ func TestWaitMultipleActivation_LogsActivationEpochOK(t *testing.T) {
resp,
nil,
)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},

View File

@@ -73,7 +73,7 @@ func TestWaitActivation_StreamSetupFails_AttemptsToReconnect(t *testing.T) {
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(clientStream, errors.New("failed stream")).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -104,7 +104,7 @@ func TestWaitForActivation_ReceiveErrorFromStream_AttemptsReconnection(t *testin
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -143,7 +143,7 @@ func TestWaitActivation_LogsActivationEpochOK(t *testing.T) {
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -178,7 +178,7 @@ func TestWaitForActivation_Exiting(t *testing.T) {
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -221,7 +221,7 @@ func TestWaitForActivation_RefetchKeys(t *testing.T) {
PublicKeys: [][]byte{kp.pub[:]},
},
).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -278,7 +278,7 @@ func TestWaitForActivation_AccountsChanged(t *testing.T) {
time.Sleep(time.Second * 2)
return inactiveClientStream, nil
})
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -370,7 +370,7 @@ func TestWaitForActivation_AccountsChanged(t *testing.T) {
time.Sleep(time.Second * 2)
return inactiveClientStream, nil
})
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},
@@ -431,7 +431,7 @@ func TestWaitActivation_NotAllValidatorsActivatedOK(t *testing.T) {
gomock.Any(),
gomock.Any(),
).Return(clientStream, nil)
prysmChainClient.EXPECT().GetValidatorCount(
prysmChainClient.EXPECT().ValidatorCount(
gomock.Any(),
"head",
[]validatorType.Status{validatorType.Active},

View File

@@ -60,7 +60,7 @@ func TestGetBeaconStatus_OK(t *testing.T) {
GenesisTime: timeStamp,
DepositContractAddress: []byte("hello"),
}, nil)
chainClient.EXPECT().GetChainHead(
chainClient.EXPECT().ChainHead(
gomock.Any(), // ctx
gomock.Any(),
).Return(&ethpb.ChainHead{
@@ -230,7 +230,7 @@ func TestServer_GetValidators(t *testing.T) {
ctrl := gomock.NewController(t)
beaconChainClient := validatormock.NewMockChainClient(ctrl)
if tt.wantErr == "" {
beaconChainClient.EXPECT().ListValidators(
beaconChainClient.EXPECT().Validators(
gomock.Any(), // ctx
tt.expectedReq,
).Return(tt.chainResp, nil)