mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 06:28:07 -05:00
Update to use electra version of go-eth2-client
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user