Skip to content

Commit

Permalink
use singleflight package to hide low-level implementation details
Browse files Browse the repository at this point in the history
  • Loading branch information
iurii-ssv committed Oct 21, 2024
1 parent 0cdfacd commit 997f01a
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 88 deletions.
18 changes: 4 additions & 14 deletions beacon/goclient/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,7 @@ func (gc *GoClient) GetAttestationData(slot phase0.Slot, committeeIndex phase0.C
}

// Have to make beacon node request and cache the result.
result, err := func() (*phase0.AttestationData, error) {
// Requests with the same slot number must lock on the same mutex.
reqMu := &gc.attestationReqMuPool[uint64(slot)%uint64(len(gc.attestationReqMuPool))]
reqMu.Lock()
defer reqMu.Unlock()

// Prevent making more than 1 beacon node requests in case somebody has already made this
// request concurrently and succeeded.
cachedResult := gc.attestationDataCache.Get(slot)
if cachedResult != nil {
return cachedResult.Value(), nil
}

result, err, _ := gc.attestationReqInflight.Do(slot, func() (*phase0.AttestationData, error) {
attDataReqStart := time.Now()
resp, err := gc.client.AttestationData(gc.ctx, &api.AttestationDataOpts{
Slot: slot,
Expand All @@ -71,10 +59,12 @@ func (gc *GoClient) GetAttestationData(slot phase0.Slot, committeeIndex phase0.C
return nil, fmt.Errorf("attestation data response is nil")
}

// Caching resulting value here (as part of inflight request) guarantees only 1 request
// will ever be done for a given slot.
gc.attestationDataCache.Set(slot, resp.Data, ttlcache.DefaultTTL)

return resp.Data, nil
}()
})
if err != nil {
return nil, DataVersionNil, err
}
Expand Down
22 changes: 10 additions & 12 deletions beacon/goclient/goclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
beaconprotocol "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon"
"github.com/ssvlabs/ssv/utils/casts"
"go.uber.org/zap"
"tailscale.com/util/singleflight"
)

const (
Expand Down Expand Up @@ -155,11 +156,9 @@ type GoClient struct {
registrationLastSlot phase0.Slot
registrationCache map[phase0.BLSPubKey]*api.VersionedSignedValidatorRegistration

// attestationReqMuPool helps us prevent the sending of multiple attestation data requests
// attestationReqInflight helps us prevent the sending of multiple attestation data requests
// for the same slot number (to avoid doing unnecessary work).
// It's a pool of mutexes (not a single mutex) to allow for some parallelism when requests
// targeting different slots are made.
attestationReqMuPool []sync.Mutex
attestationReqInflight singleflight.Group[phase0.Slot, *phase0.AttestationData]
// attestationDataCache stores attestation data from Beacon node for a bunch of recently made
// requests (by slot number). It allows for requesting attestation data once per slot from
// Beacon node as well as always having/observing the same consistent data in any given slot
Expand Down Expand Up @@ -207,14 +206,13 @@ func New(
epochDuration := time.Duration(opt.Network.SlotsPerEpoch()) * opt.Network.SlotDurationSec()

client := &GoClient{
log: logger,
ctx: opt.Context,
network: opt.Network,
client: httpClient.(*eth2clienthttp.Service),
gasLimit: opt.GasLimit,
operatorDataStore: operatorDataStore,
registrationCache: map[phase0.BLSPubKey]*api.VersionedSignedValidatorRegistration{},
attestationReqMuPool: make([]sync.Mutex, opt.Network.SlotsPerEpoch()),
log: logger,
ctx: opt.Context,
network: opt.Network,
client: httpClient.(*eth2clienthttp.Service),
gasLimit: opt.GasLimit,
operatorDataStore: operatorDataStore,
registrationCache: map[phase0.BLSPubKey]*api.VersionedSignedValidatorRegistration{},
attestationDataCache: ttlcache.New(
ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * epochDuration),
),
Expand Down
35 changes: 18 additions & 17 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/ssvlabs/ssv

go 1.22
go 1.23.1

require (
github.com/aquasecurity/table v1.8.0
Expand Down Expand Up @@ -35,7 +35,7 @@ require (
github.com/prysmaticlabs/prysm/v4 v4.0.8
github.com/rs/zerolog v1.32.0
github.com/sourcegraph/conc v0.3.0
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.8.1
github.com/ssvlabs/ssv-spec v0.3.11-0.20240820113812-496d839e9614
github.com/ssvlabs/ssv-spec-pre-cc v0.0.0-20240725052506-c48532da6a63
github.com/status-im/keycard-go v0.2.0
Expand All @@ -52,18 +52,19 @@ require (
golang.org/x/text v0.16.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
tailscale.com v1.76.3
)

require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/DataDog/zstd v1.5.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
Expand All @@ -74,10 +75,10 @@ require (
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
Expand All @@ -86,18 +87,18 @@ require (
github.com/elastic/gosigar v0.14.3 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-yaml v1.11.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/goccy/go-yaml v1.12.0 // indirect
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
Expand Down Expand Up @@ -189,7 +190,7 @@ require (
github.com/pion/turn/v2 v2.1.6 // indirect
github.com/pion/webrtc/v3 v3.3.0 // indirect
github.com/pk910/dynamic-ssz v0.0.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
Expand All @@ -199,8 +200,8 @@ require (
github.com/quic-go/webtransport-go v0.8.0 // indirect
github.com/r3labs/sse/v2 v2.10.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
Expand All @@ -219,9 +220,9 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.16.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
go.opentelemetry.io/otel/trace v1.16.0 // indirect
go.opentelemetry.io/otel v1.22.0 // indirect
go.opentelemetry.io/otel/metric v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.22.0 // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/fx v1.22.1 // indirect
golang.org/x/crypto v0.25.0 // indirect
Expand All @@ -230,7 +231,7 @@ require (
golang.org/x/term v0.22.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.23.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
gonum.org/v1/gonum v0.13.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
Expand Down
Loading

0 comments on commit 997f01a

Please sign in to comment.