Skip to content

Commit

Permalink
Implement slot fetching and caching from CL
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-ssvlabs committed Feb 3, 2025
1 parent d780ebf commit 6ad35b2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
43 changes: 41 additions & 2 deletions beacon/goclient/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/attestantio/go-eth2-client/spec"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/jellydator/ttlcache/v3"
"github.com/ssvlabs/ssv/logging/fields"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -299,19 +300,57 @@ func (gc *GoClient) scoreAttestationData(ctx context.Context,
// Initial score is based on height of source and target epochs.
score := float64(attestationData.Source.Epoch + attestationData.Target.Epoch)

//TODO: add slot values to equation. Implement cache
// Increase score based on the nearness of the head slot.
slot, err := gc.blockRootToSlot(ctx, attestationData.BeaconBlockRoot)
if err != nil {
gc.log.
With(zap.Error(err), fields.BlockRoot(attestationData.BeaconBlockRoot)).
Error("failed to obtain slot for block root")
slot = 0

Check failure on line 309 in beacon/goclient/attest.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to slot (ineffassign)
} else {
score += float64(1) / float64(1+attestationData.Slot-slot)
}

gc.log.
With(zap.String("client_addr", addr)).
With(zap.Uint64("attestation_slot", uint64(attestationData.Slot))).
With(zap.Uint64("source_epoch", uint64(attestationData.Source.Epoch))).
With(zap.Uint64("target_epoch", uint64(attestationData.Target.Epoch))).
With(zap.Float64("score", score)).
Info("scored attestation data")
Debug("scored attestation data")

return score
}

func (gc *GoClient) blockRootToSlot(ctx context.Context, root phase0.Root) (phase0.Slot, error) {
gc.blockRootToSlotMu.RLock()
slot, exists := gc.blockRootToSlotCache[root]
gc.blockRootToSlotMu.RUnlock()
if exists {
gc.log.
With(fields.BlockRoot(root)).
With(fields.Slot(slot)).
Debug("obtained slot from cache")
return slot, nil
}

gc.log.Debug("slot was not found in cache. Fetching from Consensus Client")
blockResponse, err := gc.multiClient.BeaconBlockHeader(ctx, &api.BeaconBlockHeaderOpts{
Block: root.String(),
})
if err != nil {
return 0, errors.Join(err, errors.New("failed to obtain block header"))
}

gc.log.Debug("slot was fetched from Consensus Client")

gc.blockRootToSlotMu.Lock()
gc.blockRootToSlotCache[root] = blockResponse.Data.Header.Message.Slot
gc.blockRootToSlotMu.Unlock()

return blockResponse.Data.Header.Message.Slot, nil
}

// withCommitteeIndex returns a deep copy of the attestation data with the provided committee index set.
func withCommitteeIndex(data *phase0.AttestationData, committeeIndex phase0.CommitteeIndex) (*phase0.AttestationData, error) {
// Marshal & unmarshal to make a deep copy. This is safer because it won't break silently if
Expand Down
3 changes: 3 additions & 0 deletions beacon/goclient/goclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type MultiClient interface {
eth2client.BeaconBlockRootProvider
eth2client.SyncCommitteeContributionProvider
eth2client.SyncCommitteeContributionsSubmitter
eth2client.BeaconBlockHeadersProvider
eth2client.ValidatorsProvider
eth2client.ProposalPreparationsSubmitter
eth2client.EventsProvider
Expand All @@ -126,6 +127,8 @@ type GoClient struct {
registrationLastSlot phase0.Slot
registrationCache map[phase0.BLSPubKey]*api.VersionedSignedValidatorRegistration

blockRootToSlotMu sync.RWMutex
blockRootToSlotCache map[phase0.Root]phase0.Slot
// attestationReqInflight helps prevent duplicate attestation data requests
// from running in parallel.
attestationReqInflight singleflight.Group[phase0.Slot, *phase0.AttestationData]
Expand Down

0 comments on commit 6ad35b2

Please sign in to comment.