Update to use electra version of go-eth2-client

This commit is contained in:
Chris Berry
2025-01-27 10:01:36 +00:00
parent fcafa037f8
commit 7d0e607f96
11 changed files with 163 additions and 75 deletions

View File

@@ -19,6 +19,7 @@ import (
"strconv"
"strings"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
)
@@ -27,7 +28,7 @@ type dataOut struct {
debug bool
quiet bool
verbose bool
attestation *phase0.Attestation
attestation *spec.VersionedAttestation
slot phase0.Slot
attestationIndex uint64
inclusionDelay phase0.Slot

View File

@@ -22,6 +22,7 @@ import (
eth2client "github.com/attestantio/go-eth2-client"
"github.com/attestantio/go-eth2-client/api"
apiv1 "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
standardchaintime "github.com/wealdtech/ethdo/services/chaintime/standard"
@@ -93,9 +94,17 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
return nil, errors.Wrap(err, "failed to obtain block attestations")
}
for i, attestation := range attestations {
if attestation.Data.Slot == duty.Slot &&
attestation.Data.Index == duty.CommitteeIndex &&
attestation.AggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
attestationData, err := attestation.Data()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain attestation data")
}
aggregationBits, err := attestation.AggregationBits()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain aggregation bits")
}
if attestationData.Slot == duty.Slot &&
attestationData.Index == duty.CommitteeIndex &&
aggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
headCorrect := false
targetCorrect := false
if data.verbose {
@@ -128,8 +137,12 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
return results, nil
}
func calcHeadCorrect(ctx context.Context, data *dataIn, attestation *phase0.Attestation) (bool, error) {
slot := attestation.Data.Slot
func calcHeadCorrect(ctx context.Context, data *dataIn, attestation *spec.VersionedAttestation) (bool, error) {
attestationData, err := attestation.Data()
if err != nil {
return false, errors.Wrap(err, "failed to obtain attestation data")
}
slot := attestationData.Slot
for {
response, err := data.eth2Client.(eth2client.BeaconBlockHeadersProvider).BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
Block: fmt.Sprintf("%d", slot),
@@ -149,13 +162,17 @@ func calcHeadCorrect(ctx context.Context, data *dataIn, attestation *phase0.Atte
slot--
continue
}
return bytes.Equal(response.Data.Root[:], attestation.Data.BeaconBlockRoot[:]), nil
return bytes.Equal(response.Data.Root[:], attestationData.BeaconBlockRoot[:]), nil
}
}
func calcTargetCorrect(ctx context.Context, data *dataIn, attestation *phase0.Attestation) (bool, error) {
func calcTargetCorrect(ctx context.Context, data *dataIn, attestation *spec.VersionedAttestation) (bool, error) {
attestationData, err := attestation.Data()
if err != nil {
return false, errors.Wrap(err, "failed to obtain attestation data")
}
// Start with first slot of the target epoch.
slot := data.chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
slot := data.chainTime.FirstSlotOfEpoch(attestationData.Target.Epoch)
for {
response, err := data.eth2Client.(eth2client.BeaconBlockHeadersProvider).BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
Block: fmt.Sprintf("%d", slot),
@@ -175,7 +192,7 @@ func calcTargetCorrect(ctx context.Context, data *dataIn, attestation *phase0.At
slot--
continue
}
return bytes.Equal(response.Data.Root[:], attestation.Data.Target.Root[:]), nil
return bytes.Equal(response.Data.Root[:], attestationData.Target.Root[:]), nil
}
}

View File

@@ -63,8 +63,12 @@ func (c *command) process(ctx context.Context) error {
// Calculate how many parents we need to fetch.
minSlot := slot
for _, attestation := range attestations {
if attestation.Data.Slot < minSlot {
minSlot = attestation.Data.Slot
attestData, err := attestation.Data()
if err != nil {
return errors.Wrap(err, "failed to obtain attestation data")
}
if attestData.Slot < minSlot {
minSlot = attestData.Slot
}
}
if c.debug {
@@ -103,10 +107,14 @@ func (c *command) analyzeAttestations(ctx context.Context, block *spec.Versioned
if c.debug {
fmt.Printf("Processing attestation %d\n", i)
}
attestData, err := attestation.Data()
if err != nil {
return errors.Wrap(err, "failed to obtain attestation data")
}
analysis := &attestationAnalysis{
Head: attestation.Data.BeaconBlockRoot,
Target: attestation.Data.Target.Root,
Distance: int(slot - attestation.Data.Slot),
Head: attestData.BeaconBlockRoot,
Target: attestData.Target.Root,
Distance: int(slot - attestData.Slot),
}
root, err := attestation.HashTreeRoot()
@@ -116,45 +124,47 @@ func (c *command) analyzeAttestations(ctx context.Context, block *spec.Versioned
if info, exists := c.priorAttestations[fmt.Sprintf("%#x", root)]; exists {
analysis.Duplicate = info
} else {
data := attestation.Data
_, exists := blockVotes[data.Slot]
if !exists {
blockVotes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
aggregationBits, err := attestation.AggregationBits()
if err != nil {
return err
}
_, exists = blockVotes[data.Slot][data.Index]
_, exists := blockVotes[attestData.Slot]
if !exists {
blockVotes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
blockVotes[attestData.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
}
_, exists = blockVotes[attestData.Slot][attestData.Index]
if !exists {
blockVotes[attestData.Slot][attestData.Index] = bitfield.NewBitlist(aggregationBits.Len())
}
// Count new votes.
analysis.PossibleVotes = int(attestation.AggregationBits.Len())
for j := range attestation.AggregationBits.Len() {
if attestation.AggregationBits.BitAt(j) {
analysis.PossibleVotes = int(aggregationBits.Len())
for j := range aggregationBits.Len() {
if aggregationBits.BitAt(j) {
analysis.Votes++
if blockVotes[data.Slot][data.Index].BitAt(j) {
if blockVotes[attestData.Slot][attestData.Index].BitAt(j) {
// Already attested to in this block; skip.
continue
}
if c.votes[data.Slot][data.Index].BitAt(j) {
if c.votes[attestData.Slot][attestData.Index].BitAt(j) {
// Already attested to in a previous block; skip.
continue
}
analysis.NewVotes++
blockVotes[data.Slot][data.Index].SetBitAt(j, true)
blockVotes[attestData.Slot][attestData.Index].SetBitAt(j, true)
}
}
// Calculate head correct.
var err error
analysis.HeadCorrect, err = c.calcHeadCorrect(ctx, attestation)
if err != nil {
return err
}
// Calculate head timely.
analysis.HeadTimely = analysis.HeadCorrect && attestation.Data.Slot == slot-1
analysis.HeadTimely = analysis.HeadCorrect && attestData.Slot == slot-1
// Calculate source timely.
analysis.SourceTimely = attestation.Data.Slot >= slot-5
analysis.SourceTimely = attestData.Slot >= slot-5
// Calculate target correct.
analysis.TargetCorrect, err = c.calcTargetCorrect(ctx, attestation)
@@ -164,7 +174,7 @@ func (c *command) analyzeAttestations(ctx context.Context, block *spec.Versioned
// Calculate target timely.
if block.Version < spec.DataVersionDeneb {
analysis.TargetTimely = attestation.Data.Slot >= slot-32
analysis.TargetTimely = attestData.Slot >= slot-32
} else {
analysis.TargetTimely = true
}
@@ -260,17 +270,24 @@ func (c *command) processParentBlock(_ context.Context, block *spec.VersionedSig
Index: i,
}
data := attestation.Data
data, err := attestation.Data()
if err != nil {
return err
}
_, exists := c.votes[data.Slot]
if !exists {
c.votes[data.Slot] = make(map[phase0.CommitteeIndex]bitfield.Bitlist)
}
_, exists = c.votes[data.Slot][data.Index]
if !exists {
c.votes[data.Slot][data.Index] = bitfield.NewBitlist(attestation.AggregationBits.Len())
aggregationBits, err := attestation.AggregationBits()
if err != nil {
return err
}
for j := range attestation.AggregationBits.Len() {
if attestation.AggregationBits.BitAt(j) {
if !exists {
c.votes[data.Slot][data.Index] = bitfield.NewBitlist(aggregationBits.Len())
}
for j := range aggregationBits.Len() {
if aggregationBits.BitAt(j) {
c.votes[data.Slot][data.Index].SetBitAt(j, true)
}
}
@@ -385,8 +402,12 @@ func (c *command) setup(ctx context.Context) error {
return nil
}
func (c *command) calcHeadCorrect(ctx context.Context, attestation *phase0.Attestation) (bool, error) {
slot := attestation.Data.Slot
func (c *command) calcHeadCorrect(ctx context.Context, attestation *spec.VersionedAttestation) (bool, error) {
attestData, err := attestation.Data()
if err != nil {
return false, errors.Wrap(err, "failed to obtain attestation data")
}
slot := attestData.Slot
root, exists := c.headRoots[slot]
if !exists {
for {
@@ -413,20 +434,24 @@ func (c *command) calcHeadCorrect(ctx context.Context, attestation *phase0.Attes
slot--
continue
}
c.headRoots[attestation.Data.Slot] = response.Data.Root
c.headRoots[attestData.Slot] = response.Data.Root
root = response.Data.Root
break
}
}
return bytes.Equal(root[:], attestation.Data.BeaconBlockRoot[:]), nil
return bytes.Equal(root[:], attestData.BeaconBlockRoot[:]), nil
}
func (c *command) calcTargetCorrect(ctx context.Context, attestation *phase0.Attestation) (bool, error) {
root, exists := c.targetRoots[attestation.Data.Slot]
func (c *command) calcTargetCorrect(ctx context.Context, attestation *spec.VersionedAttestation) (bool, error) {
attestData, err := attestation.Data()
if err != nil {
return false, errors.Wrap(err, "failed to obtain attestation data")
}
root, exists := c.targetRoots[attestData.Slot]
if !exists {
// Start with first slot of the target epoch.
slot := c.chainTime.FirstSlotOfEpoch(attestation.Data.Target.Epoch)
slot := c.chainTime.FirstSlotOfEpoch(attestData.Target.Epoch)
for {
response, err := c.blockHeadersProvider.BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
Block: fmt.Sprintf("%d", slot),
@@ -450,12 +475,12 @@ func (c *command) calcTargetCorrect(ctx context.Context, attestation *phase0.Att
slot--
continue
}
c.targetRoots[attestation.Data.Slot] = response.Data.Root
c.targetRoots[attestData.Slot] = response.Data.Root
root = response.Data.Root
break
}
}
return bytes.Equal(root[:], attestation.Data.Target.Root[:]), nil
return bytes.Equal(root[:], attestData.Target.Root[:]), nil
}
func (c *command) analyzeSyncCommittees(_ context.Context, block *spec.VersionedSignedBeaconBlock) error {

View File

@@ -239,17 +239,21 @@ func (c *command) processSlots(ctx context.Context,
return nil, nil, nil, nil, nil, nil, nil, err
}
for _, attestation := range attestations {
if attestation.Data.Slot < c.chainTime.FirstSlotOfEpoch(c.summary.Epoch) || attestation.Data.Slot >= c.chainTime.FirstSlotOfEpoch(c.summary.Epoch+1) {
attestationData, err := attestation.Data()
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, "failed to obtain attestation data")
}
if attestationData.Slot < c.chainTime.FirstSlotOfEpoch(c.summary.Epoch) || attestationData.Slot >= c.chainTime.FirstSlotOfEpoch(c.summary.Epoch+1) {
// Outside of this epoch's range.
continue
}
slotCommittees, exists := allCommittees[attestation.Data.Slot]
slotCommittees, exists := allCommittees[attestationData.Slot]
if !exists {
response, err := c.beaconCommitteesProvider.BeaconCommittees(ctx, &api.BeaconCommitteesOpts{
State: fmt.Sprintf("%d", attestation.Data.Slot),
State: fmt.Sprintf("%d", attestationData.Slot),
})
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain committees for slot %d", attestation.Data.Slot))
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, fmt.Sprintf("failed to obtain committees for slot %d", attestationData.Slot))
}
for _, beaconCommittee := range response.Data {
if _, exists := allCommittees[beaconCommittee.Slot]; !exists {
@@ -275,11 +279,11 @@ func (c *command) processSlots(ctx context.Context,
}
}
}
slotCommittees = allCommittees[attestation.Data.Slot]
slotCommittees = allCommittees[attestationData.Slot]
}
committee := slotCommittees[attestation.Data.Index]
committee := slotCommittees[attestationData.Index]
inclusionDistance := slot - attestation.Data.Slot
inclusionDistance := slot - attestationData.Slot
head, err := util.AttestationHead(ctx, headersCache, attestation)
if err != nil {
@@ -298,8 +302,12 @@ func (c *command) processSlots(ctx context.Context,
return nil, nil, nil, nil, nil, nil, nil, err
}
for i := range attestation.AggregationBits.Len() {
if attestation.AggregationBits.BitAt(i) {
aggregationBits, err := attestation.AggregationBits()
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, errors.Wrap(err, "failed to obtain aggregation bits")
}
for i := range aggregationBits.Len() {
if aggregationBits.BitAt(i) {
validatorIndex := committee[int(i)]
if len(c.validators) > 0 {
if _, exists := c.validators[validatorIndex]; !exists {
@@ -310,9 +318,9 @@ func (c *command) processSlots(ctx context.Context,
// Only set the information from the first attestation we find for this validator.
if participations[validatorIndex].InclusionSlot == 0 {
participations[validatorIndex].HeadVote = &attestation.Data.BeaconBlockRoot
participations[validatorIndex].HeadVote = &attestationData.BeaconBlockRoot
participations[validatorIndex].Head = &head
participations[validatorIndex].TargetVote = &attestation.Data.Target.Root
participations[validatorIndex].TargetVote = &attestationData.Target.Root
participations[validatorIndex].Target = &target
participations[validatorIndex].InclusionSlot = slot
}

View File

@@ -243,16 +243,24 @@ func (c *command) processAttesterDutiesSlot(ctx context.Context,
return err
}
for _, attestation := range attestations {
if _, exists := dutiesBySlot[attestation.Data.Slot]; !exists {
attestationData, err := attestation.Data()
if err != nil {
return errors.Wrap(err, "failed to obtain attestation data")
}
if _, exists := dutiesBySlot[attestationData.Slot]; !exists {
// We do not have any attestations for this slot.
continue
}
if _, exists := dutiesBySlot[attestation.Data.Slot][attestation.Data.Index]; !exists {
if _, exists := dutiesBySlot[attestationData.Slot][attestationData.Index]; !exists {
// We do not have any attestations for this committee.
continue
}
for _, duty := range dutiesBySlot[attestation.Data.Slot][attestation.Data.Index] {
if attestation.AggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
for _, duty := range dutiesBySlot[attestationData.Slot][attestationData.Index] {
aggregationBits, err := attestation.AggregationBits()
if err != nil {
return errors.Wrap(err, "failed to obtain aggregation bits")
}
if aggregationBits.BitAt(duty.ValidatorCommitteeIndex) {
// Found it.
if _, exists := votes[duty.ValidatorIndex]; exists {
// Duplicate; ignore.
@@ -261,13 +269,13 @@ func (c *command) processAttesterDutiesSlot(ctx context.Context,
votes[duty.ValidatorIndex] = struct{}{}
// Update the metrics for the attestation.
index := int(attestation.Data.Slot - c.chainTime.FirstSlotOfEpoch(c.summary.Epoch))
index := int(attestationData.Slot - c.chainTime.FirstSlotOfEpoch(c.summary.Epoch))
c.summary.Slots[index].Attestations.Included++
inclusionDelay := slot - duty.Slot
fault := &validatorFault{
Validator: duty.ValidatorIndex,
AttestationData: attestation.Data,
AttestationData: attestationData,
InclusionDistance: int(inclusionDelay),
}