From a312ef37634b8ca0ecbd57c0c3c5eea123857f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Sun, 30 Oct 2022 18:56:19 +0200 Subject: [PATCH 1/9] Add OpenTelemetry tracing instrumentation Initial commit for adding OT tracing using a customizable endpoint --- .golangci.yml | 2 +- DEVELOPMENT.md | 59 +- chain/beacon/callbacks_test.go | 6 +- chain/beacon/chainstore.go | 86 ++- chain/beacon/node.go | 209 ++++-- chain/beacon/node_test.go | 58 +- chain/beacon/store.go | 33 +- chain/beacon/store_test.go | 2 +- chain/beacon/sync_manager.go | 101 ++- chain/boltdb/store.go | 44 +- chain/boltdb/store_test.go | 10 +- chain/boltdb/trimmed.go | 43 +- chain/boltdb/trimmed_test.go | 8 +- chain/memdb/store.go | 58 +- chain/memdb/store_test.go | 8 +- chain/postgresdb/database/database.go | 16 +- chain/postgresdb/pgdb/pgdb.go | 56 +- chain/postgresdb/pgdb/pgdb_test.go | 12 +- chain/postgresdb/schema/schema.go | 4 + chain/store.go | 2 +- client/test/http/mock/httpserver.go | 3 +- cmd/drand-cli/cli.go | 39 +- cmd/drand-cli/cli_test.go | 2 +- cmd/drand-cli/daemon.go | 26 +- cmd/drand-cli/public.go | 3 +- cmd/relay/main.go | 24 +- core/client_public.go | 8 +- core/config.go | 28 +- core/drand_beacon.go | 54 +- core/drand_beacon_control.go | 92 ++- core/drand_beacon_metrics.go | 9 +- core/drand_beacon_public.go | 33 +- core/drand_beacon_test.go | 12 +- core/drand_daemon.go | 90 ++- core/drand_daemon_control.go | 54 +- core/drand_daemon_interceptors.go | 4 + core/drand_daemon_public.go | 30 +- core/drand_daemon_test.go | 10 +- core/drand_test.go | 18 +- core/util_test.go | 22 +- demo/main.go | 1 + demo/node/node_inprocess.go | 13 +- .../provisioning/datasources/datasources.yaml | 49 ++ devenv/conf/loki.yaml | 40 ++ devenv/conf/prom.yaml | 29 + devenv/conf/tempo.yaml | 62 ++ devenv/docker-compose.yaml | 86 +++ dkg/broadcast.go | 98 ++- docker-compose.yaml | 18 + go.mod | 96 ++- go.sum | 637 ++++++++++++++---- http/server.go | 55 +- http/server_test.go | 9 + key/store.go | 2 +- metrics/metrics.go | 9 +- metrics/metrics_test.go | 8 +- metrics/tracer.go | 132 ++++ net/client.go | 2 +- net/client_grpc.go | 42 +- net/listener.go | 34 +- net/peer.go | 6 +- test/docker-compose.yaml | 10 - test/key_store.go | 2 +- test/metrics.go | 34 + 64 files changed, 2299 insertions(+), 553 deletions(-) create mode 100644 devenv/conf/grafana/provisioning/datasources/datasources.yaml create mode 100644 devenv/conf/loki.yaml create mode 100644 devenv/conf/prom.yaml create mode 100644 devenv/conf/tempo.yaml create mode 100644 devenv/docker-compose.yaml create mode 100644 docker-compose.yaml create mode 100644 metrics/tracer.go delete mode 100644 test/docker-compose.yaml create mode 100644 test/metrics.go diff --git a/.golangci.yml b/.golangci.yml index c7580339a..eefca7f58 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -74,7 +74,7 @@ linters: - goimports # -golint # Deprecated - gomnd - - gomoddirectives + #- gomoddirectives - gomodguard - goprintffuncname - gosec diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d4a5f8b19..26b753eab 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -21,6 +21,55 @@ correct development environment tools installed: Finally, if you ran all the above commands and `git status` does not report any changes to the repository, then you are ready to start. +### Development environment + +Certain features in Drand depend on external services. +These features are the support for running with PostgreSQL as a database backend, and observability features such as metrics, and tracing. + +To keep your environment clean from any external tools required to interact with such features, you can use the +`docker-compose.yaml` file under `devenv/docker-compose.yaml`. + +#### Using the devenv tools + +To launch the tools, run +```shell +cd devenv +docker compose up -d +``` + +If you wish to stop the stack, run: +```shell +docker compose down +``` + +To cleanup and remove all data, run: +```shell +cd devenv +docker compose down --volumes --remove-orphans +``` + +#### PostgreSQL backend + +To use the database instance provided with the devenv, use `127.0.0.1:5432` as the destination for PostgreSQL. + +For more details, see the [testing section below](#testing-with-postgresql-as-database-backend). + +#### Observability features + +Drand can produce traces compatible with OpenTelemetry specification. To turn on this feature, set the `DRAND_TRACES` +environment varible to the desired destination, e.g. +```shell +export DRAND_TRACES=127.0.0.1:4317 +export DRAND_TRACES_PROBABILITY=1 # This will sample all traces to the destination server +``` + +After that, in the same terminal, use any of the drand features, such as `make test-unit-memdb`, to start producing traces. + +To explore the trace details, launch a new browser tab/window at the [Grafana instance](http://127.0.0.1:3000/explore?orgId=1), +which will allow you to explore in detail the inner workings of Drand. + +For more details on how to use Grafana, you can [read the manual here](https://grafana.com/docs/grafana/v9.4/explore/trace-integration/). + ### Development flow After editing all files required by your change: @@ -54,23 +103,23 @@ To check your code against it, run `make test-unit-postgres`. You can also run the `make demo-postgres` command to launch the scripted demo using PostgreSQL as a backend. -If you want to run an isolated version of Postgres, you can use the `test/docker-compose.yaml` file +If you want to run an isolated version of Postgres, you can use the `devenv/docker-compose.yaml` file from the root of this repository to do so. To start the database, use: ```shell -cd test/ -docker-compose up -d +cd devenv/ +docker compose up -d ``` To stop the database, use: ```shell -docker-compose down +docker compose down ``` If you wish to remove the database volume too, use this command instead to stop: ```shell -docker-compose down --volumes --remove-orphans +docker compose down --volumes --remove-orphans ``` ## Regression testing diff --git a/chain/beacon/callbacks_test.go b/chain/beacon/callbacks_test.go index 00a8fe447..731d21eac 100644 --- a/chain/beacon/callbacks_test.go +++ b/chain/beacon/callbacks_test.go @@ -29,15 +29,17 @@ func TestStoreCallback(t *testing.T) { doneCh <- true }) - cb.Put(ctx, &chain.Beacon{ + err = cb.Put(ctx, &chain.Beacon{ Round: 1, }) + require.NoError(t, err) require.True(t, checkOne(doneCh)) cb.AddCallback(id1, func(*chain.Beacon, bool) {}) - cb.Put(ctx, &chain.Beacon{ + err = cb.Put(ctx, &chain.Beacon{ Round: 1, }) + require.NoError(t, err) require.False(t, checkOne(doneCh)) cb.RemoveCallback(id1) diff --git a/chain/beacon/chainstore.go b/chain/beacon/chainstore.go index 710d828cf..236343889 100644 --- a/chain/beacon/chainstore.go +++ b/chain/beacon/chainstore.go @@ -5,10 +5,14 @@ import ( "errors" "fmt" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" + "github.com/drand/drand/chain" "github.com/drand/drand/crypto/vault" "github.com/drand/drand/key" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/drand" ) @@ -40,19 +44,25 @@ type chainStore struct { beaconStoredAgg chan *chain.Beacon } -func newChainStore(l log.Logger, cf *Config, cl net.ProtocolClient, v *vault.Vault, store chain.Store, t *ticker) (*chainStore, error) { +//nolint:lll // The names are long but clear +func newChainStore(ctx context.Context, l log.Logger, cf *Config, cl net.ProtocolClient, v *vault.Vault, store chain.Store, t *ticker) (*chainStore, error) { + ctx, span := metrics.NewSpan(ctx, "newChainStore") + defer span.End() + // we write some stats about the timing when new beacon is saved ds := newDiscrepancyStore(store, l, v.GetGroup(), cf.Clock) // we add a store to run some checks depending on scheme-related config - ss, err := NewSchemeStore(ds, cf.Group.Scheme) + ss, err := NewSchemeStore(ctx, ds, cf.Group.Scheme) if err != nil { + span.RecordError(err) return nil, err } // we make sure the chain is increasing monotonically - as, err := newAppendStore(ss) + as, err := newAppendStore(ctx, ss) if err != nil { + span.RecordError(err) return nil, err } @@ -60,7 +70,7 @@ func newChainStore(l log.Logger, cf *Config, cl net.ProtocolClient, v *vault.Vau cbs := NewCallbackStore(l, as) // we give the final append store to the sync manager - syncm, err := NewSyncManager(&SyncConfig{ + syncm, err := NewSyncManager(ctx, &SyncConfig{ Log: l, Store: cbs, BoltdbStore: store, @@ -70,6 +80,7 @@ func newChainStore(l log.Logger, cf *Config, cl net.ProtocolClient, v *vault.Vau NodeAddr: cf.Public.Address(), }) if err != nil { + span.RecordError(err) return nil, err } go syncm.Run() @@ -99,12 +110,16 @@ func newChainStore(l log.Logger, cf *Config, cl net.ProtocolClient, v *vault.Vau cs.beaconStoredAgg <- b }) // TODO maybe look if it's worth having multiple workers there - go cs.runAggregator() + go func() { + cs.runAggregator() + }() return cs, nil } -func (c *chainStore) NewValidPartial(addr string, p *drand.PartialBeaconPacket) { +func (c *chainStore) NewValidPartial(spanContext oteltrace.SpanContext, addr string, p *drand.PartialBeaconPacket) { c.newPartials <- partialInfo{ + spanContext: spanContext, + addr: addr, p: p, } @@ -114,7 +129,7 @@ func (c *chainStore) Stop() { c.ctxCancel() c.syncm.Stop() c.RemoveCallback("chainstore") - c.CallbackStore.Close(context.Background()) + c.CallbackStore.Close() } // we store partials that are up to this amount of rounds more than the last @@ -143,18 +158,29 @@ func (c *chainStore) runAggregator() { case lastBeacon = <-c.beaconStoredAgg: cache.FlushRounds(lastBeacon.Round) case partial := <-c.newPartials: + ctx, span := metrics.NewSpanFromSpanContext(c.ctx, partial.spanContext, "c.runAggregator") + + span.SetAttributes( + attribute.Int64("round", int64(partial.p.Round)), + attribute.String("addr", partial.addr), + ) + var err error if lastBeacon == nil { - lastBeacon, err = c.Last(c.ctx) + lastBeacon, err = c.Last(ctx) if err != nil { + span.RecordError(err) if errors.Is(err, context.Canceled) { c.l.Errorw("stopping chain_aggregator", "loading", "last_beacon", "err", err) + span.End() return } if err.Error() == "sql: database is closed" { c.l.Errorw("stopping chain_aggregator", "loading", "last_beacon", "err", err) + span.End() return } + span.End() c.l.Fatalw("stopping chain_aggregator", "loading", "last_beacon", "err", err) } } @@ -167,7 +193,9 @@ func (c *chainStore) runAggregator() { shouldStore := isNotInPast && isNotTooFar // check if we can reconstruct if !shouldStore { + span.AddEvent("ignoring_partial") c.l.Debugw("", "ignoring_partial", partial.p.GetRound(), "last_beacon_stored", lastBeacon.Round) + span.End() break } // NOTE: This line means we can only verify partial signatures of @@ -179,7 +207,9 @@ func (c *chainStore) runAggregator() { n := c.crypto.GetGroup().Len() select { - case <-c.ctx.Done(): + case <-ctx.Done(): + span.AddEvent("ctx.Done") + span.End() return default: } @@ -188,12 +218,16 @@ func (c *chainStore) runAggregator() { roundCache := cache.GetRoundCache(partial.p.GetRound(), partial.p.GetPreviousSignature()) if roundCache == nil { c.l.Errorw("", "store_partial", partial.addr, "no_round_cache", partial.p.GetRound()) + span.RecordError(errors.New("no round cache")) + span.End() break } c.l.Debugw("", "store_partial", partial.addr, "round", roundCache.round, "len_partials", fmt.Sprintf("%d/%d", roundCache.Len(), thr)) if roundCache.Len() < thr { + span.AddEvent("roundCache.Len < thr") + span.End() break } @@ -202,13 +236,19 @@ func (c *chainStore) runAggregator() { finalSig, err := c.crypto.Scheme.ThresholdScheme.Recover(c.crypto.GetPub(), msg, roundCache.Partials(), thr, n) if err != nil { c.l.Errorw("invalid_recovery", "error", err, "round", pRound, "got", fmt.Sprintf("%d/%d", roundCache.Len(), n)) + span.RecordError(errors.New("invalid recovery")) break } if err := c.crypto.Scheme.ThresholdScheme.VerifyRecovered(c.crypto.GetPub().Commit(), msg, finalSig); err != nil { c.l.Errorw("invalid_sig", "error", err, "round", pRound) + span.RecordError(errors.New("invalid signature")) + span.End() break } + + span.AddEvent("cache.FlushRounds") cache.FlushRounds(partial.p.GetRound()) + span.AddEvent("cache.FlushRounds - done") newBeacon := &chain.Beacon{ Round: roundCache.round, @@ -217,13 +257,17 @@ func (c *chainStore) runAggregator() { } c.l.Infow("", "aggregated_beacon", newBeacon.Round) - if c.tryAppend(c.ctx, lastBeacon, newBeacon) { + span.AddEvent("calling tryAppend") + if c.tryAppend(ctx, lastBeacon, newBeacon) { lastBeacon = newBeacon + span.End() break } select { case <-c.ctx.Done(): + span.AddEvent("ctx.Done") + span.End() return default: } @@ -232,13 +276,17 @@ func (c *chainStore) runAggregator() { c.l.Debugw("", "new_aggregated", "not_appendable", "last", lastBeacon.String(), "new", newBeacon.String()) if c.shouldSync(lastBeacon, newBeacon) { peers := toPeers(c.crypto.GetGroup().Nodes) - c.syncm.SendSyncRequest(newBeacon.Round, peers) + c.syncm.SendSyncRequest(span.SpanContext(), newBeacon.Round, peers) } + span.End() } } } func (c *chainStore) tryAppend(ctx context.Context, last, newB *chain.Beacon) bool { + ctx, span := metrics.NewSpan(ctx, "chainStore.tryAppend") + defer span.End() + select { case <-ctx.Done(): return false @@ -251,6 +299,7 @@ func (c *chainStore) tryAppend(ctx context.Context, last, newB *chain.Beacon) bo } if err := c.CallbackStore.Put(ctx, newB); err != nil { + span.RecordError(err) // if round is ok but bytes are different, error will be raised if errors.Is(err, ErrBeaconAlreadyStored) { c.l.Debugw("Put: race with SyncManager", "err", err) @@ -289,16 +338,22 @@ func (c *chainStore) shouldSync(last *chain.Beacon, newB likeBeacon) bool { // It will start from the latest stored beacon. If upTo is equal to 0, then it // will follow the chain indefinitely. If peers is nil, it uses the peers of // the current group. -func (c *chainStore) RunSync(upTo uint64, peers []net.Peer) { +func (c *chainStore) RunSync(ctx context.Context, upTo uint64, peers []net.Peer) { + _, span := metrics.NewSpan(ctx, "c.RunSync") + defer span.End() + if len(peers) == 0 { peers = toPeers(c.crypto.GetGroup().Nodes) } - c.syncm.SendSyncRequest(upTo, peers) + c.syncm.SendSyncRequest(span.SpanContext(), upTo, peers) } // RunReSync will sync up with other nodes to repair the invalid beacons in the store. func (c *chainStore) RunReSync(ctx context.Context, faultyBeacons []uint64, peers []net.Peer, cb func(r, u uint64)) error { + ctx, span := metrics.NewSpan(ctx, "c.RunReSync") + defer span.End() + // we do this check here because the SyncManager doesn't have the notion of group if len(peers) == 0 { peers = toPeers(c.crypto.GetGroup().Nodes) @@ -311,6 +366,9 @@ func (c *chainStore) RunReSync(ctx context.Context, faultyBeacons []uint64, peer // and it returns the list of round numbers for which the beacons were corrupted / invalid / not found in the store. // Note: it does not attempt to correct or fetch these faulty beacons. func (c *chainStore) ValidateChain(ctx context.Context, upTo uint64, cb func(r, u uint64)) ([]uint64, error) { + ctx, span := metrics.NewSpan(ctx, "c.ValidateChain") + defer span.End() + return c.syncm.CheckPastBeacons(ctx, upTo, cb) } @@ -319,6 +377,8 @@ func (c *chainStore) AppendedBeaconNoSync() chan *chain.Beacon { } type partialInfo struct { + spanContext oteltrace.SpanContext + addr string p *drand.PartialBeaconPacket } diff --git a/chain/beacon/node.go b/chain/beacon/node.go index 6ed5a3154..73377b003 100644 --- a/chain/beacon/node.go +++ b/chain/beacon/node.go @@ -9,12 +9,14 @@ import ( "time" clock "github.com/jonboulle/clockwork" + "go.opentelemetry.io/otel/attribute" "github.com/drand/drand/chain" commonutils "github.com/drand/drand/common" "github.com/drand/drand/crypto/vault" "github.com/drand/drand/key" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/common" proto "github.com/drand/drand/protobuf/drand" @@ -62,27 +64,38 @@ type Handler struct { } // NewHandler returns a fresh handler ready to serve and create randomness -// beacon -func NewHandler(c net.ProtocolClient, s chain.Store, conf *Config, l log.Logger, version commonutils.Version) (*Handler, error) { +// beacon. +// +//nolint:lll // This is a complex function +func NewHandler(ctx context.Context, c net.ProtocolClient, s chain.Store, conf *Config, l log.Logger, version commonutils.Version) (*Handler, error) { + ctx, span := metrics.NewSpan(ctx, "NewHandler") + defer span.End() + if conf.Share == nil || conf.Group == nil { - return nil, errors.New("beacon: invalid configuration") + err := errors.New("beacon: invalid configuration") + span.RecordError(err) + return nil, err } // Checking we are in the group node := conf.Group.Find(conf.Public.Identity) if node == nil { - return nil, errors.New("beacon: keypair not included in the given group") + err := errors.New("beacon: keypair not included in the given group") + span.RecordError(err) + return nil, err } addr := conf.Public.Address() v := vault.NewVault(l, conf.Group, conf.Share, conf.Group.Scheme) // insert genesis beacon - if err := s.Put(context.Background(), chain.GenesisBeacon(conf.Group.GenesisSeed)); err != nil { + if err := s.Put(ctx, chain.GenesisBeacon(conf.Group.GenesisSeed)); err != nil { + span.RecordError(err) return nil, err } ticker := newTicker(conf.Clock, conf.Group.Period, conf.Group.GenesisTime) - store, err := newChainStore(l, conf, c, v, s, ticker) + store, err := newChainStore(ctx, l, conf, c, v, s, ticker) if err != nil { + span.RecordError(err) return nil, err } @@ -106,8 +119,11 @@ func NewHandler(c net.ProtocolClient, s chain.Store, conf *Config, l log.Logger, // ProcessPartialBeacon receives a request for a beacon partial signature. It // forwards it to the round manager if it is a valid beacon. -func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeaconPacket) (*proto.Empty, error) { - addr := net.RemoteAddress(c) +func (h *Handler) ProcessPartialBeacon(ctx context.Context, p *proto.PartialBeaconPacket) (*proto.Empty, error) { + ctx, span := metrics.NewSpan(ctx, "h.ProcessPartialBeacon") + defer span.End() + + addr := net.RemoteAddress(ctx) pRound := p.GetRound() h.l.Debugw("", "received", "request", "from", addr, "round", pRound) @@ -123,21 +139,28 @@ func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeacon } // we don't want to process partials for beacons that we've already stored. - if latest, err := h.chain.Last(c); err == nil && pRound <= latest.GetRound() { + if latest, err := h.chain.Last(ctx); err == nil && pRound <= latest.GetRound() { h.l.Debugw("ignoring past partial", "from", addr, "round", pRound, "current_round", currentRound, "latestStored", latest.GetRound()) + span.RecordError(fmt.Errorf("invalid past partial")) return new(proto.Empty), nil } + span.AddEvent("h.crypto.DigestBeacon") msg := h.crypto.DigestBeacon(&chain.Beacon{Round: pRound, PreviousSig: p.GetPreviousSignature()}) + span.AddEvent("h.crypto.DigestBeacon - done") idx, _ := h.crypto.ThresholdScheme.IndexOf(p.GetPartialSig()) if idx < 0 { - return nil, fmt.Errorf("invalid index %d in partial with msg %v partial_round %v", idx, msg, pRound) + err := fmt.Errorf("invalid index %d in partial with msg %v partial_round %v", idx, msg, pRound) + span.RecordError(err) + return nil, err } node := h.crypto.GetGroup().Node(uint32(idx)) if node == nil { - return nil, fmt.Errorf("attempted to process beacon from node of index %d, but it was not in the group file", uint32(idx)) + err := fmt.Errorf("attempted to process beacon from node of index %d, but it was not in the group file", uint32(idx)) + span.RecordError(err) + return nil, err } nodeName := node.Address() @@ -147,7 +170,11 @@ func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeacon } // verify if request is valid - if err := h.crypto.ThresholdScheme.VerifyPartial(h.crypto.GetPub(), msg, p.GetPartialSig()); err != nil { + span.AddEvent("h.crypto.ThresholdScheme.VerifyPartial") + err := h.crypto.ThresholdScheme.VerifyPartial(h.crypto.GetPub(), msg, p.GetPartialSig()) + span.AddEvent("h.crypto.ThresholdScheme.VerifyPartial - done") + + if err != nil { h.l.Errorw("", "process_partial", addr, "err", err, "prev_sig", shortSigStr(p.GetPreviousSignature()), @@ -156,8 +183,10 @@ func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeacon "msg_sign", shortSigStr(msg), "from_idx", idx, "from_node", nodeName) + span.RecordError(err) return nil, err } + h.l.Debugw("", "process_partial", addr, "prev_sig", shortSigStr(p.GetPreviousSignature()), @@ -166,6 +195,7 @@ func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeacon "msg_sign", shortSigStr(msg), "from_node", nodeName, "status", "OK") + if idx == h.crypto.Index() { h.l.Errorw("", "process_partial", addr, @@ -176,7 +206,8 @@ func (h *Handler) ProcessPartialBeacon(c context.Context, p *proto.PartialBeacon // XXX error or not ? return new(proto.Empty), nil } - h.chain.NewValidPartial(addr, p) + + h.chain.NewValidPartial(span.SpanContext(), addr, p) return new(proto.Empty), nil } @@ -192,7 +223,10 @@ func (h *Handler) Store() CallbackStore { // SyncAndRun(). // Round 0 = genesis seed - fixed // Round 1 starts at genesis time, and is signing over the genesis seed -func (h *Handler) Start() error { +func (h *Handler) Start(ctx context.Context) error { + _, span := metrics.NewSpan(ctx, "h.Handler") + defer span.End() + if h.conf.Clock.Now().Unix() > h.conf.Group.GenesisTime { h.l.Errorw("", "genesis_time", "past", "call", "catchup") return errors.New("beacon: genesis time already passed. Call Catchup()") @@ -215,21 +249,27 @@ func (h *Handler) Start() error { // already running network . If the node does not have the previous randomness, // it sync its local chain with other nodes to be able to participate in the // next upcoming round. -func (h *Handler) Catchup() { +func (h *Handler) Catchup(ctx context.Context) { + ctx, span := metrics.NewSpan(ctx, "h.Catchup") + defer span.End() + h.Lock() h.started = true h.Unlock() nRound, tTime := chain.NextRound(h.conf.Clock.Now().Unix(), h.conf.Group.Period, h.conf.Group.GenesisTime) go h.run(tTime) - h.chain.RunSync(nRound, nil) + h.chain.RunSync(ctx, nRound, nil) } // Transition makes this beacon continuously sync until the time written in the // "TransitionTime" in the handler's group file, where he will start generating // randomness. To sync, he contacts the nodes listed in the previous group file // given. -func (h *Handler) Transition(prevGroup *key.Group) error { +func (h *Handler) Transition(ctx context.Context, prevGroup *key.Group) error { + ctx, span := metrics.NewSpan(ctx, "h.Transition") + defer span.End() + targetTime := h.conf.Group.TransitionTime tRound := chain.CurrentRound(targetTime, h.conf.Group.Period, h.conf.Group.GenesisTime) tTime := chain.TimeOfRound(h.conf.Group.Period, h.conf.Group.GenesisTime, tRound) @@ -246,16 +286,20 @@ func (h *Handler) Transition(prevGroup *key.Group) error { // we run the sync up until (inclusive) one round before the transition h.l.Debugw("", "new_node", "following chain", "to_round", tRound-1) - h.chain.RunSync(tRound-1, toPeers(prevGroup.Nodes)) + h.chain.RunSync(ctx, tRound-1, toPeers(prevGroup.Nodes)) return nil } // TransitionNewGroup prepares the node to transition to the new group -func (h *Handler) TransitionNewGroup(newShare *key.Share, newGroup *key.Group) { +func (h *Handler) TransitionNewGroup(ctx context.Context, newShare *key.Share, newGroup *key.Group) { if h == nil { return } + + _, span := metrics.NewSpan(ctx, "h.TransitionNewGroup") + defer span.End() + targetTime := newGroup.TransitionTime tRound := chain.CurrentRound(targetTime, h.conf.Group.Period, h.conf.Group.GenesisTime) @@ -309,7 +353,10 @@ func (h *Handler) IsStopped() bool { return h.stopped } -func (h *Handler) Reset() { +func (h *Handler) Reset(ctx context.Context) { + _, span := metrics.NewSpan(ctx, "h.Reset") + defer span.End() + h.Lock() defer h.Unlock() @@ -346,35 +393,48 @@ func (h *Handler) run(startTime int64) { h.l.Debugw("", "beacon_loop", "finished", "err", h.ctx.Err()) return case current = <-chanTick: + func() { + ctx, span := metrics.NewSpan(h.ctx, "h.run.chanTick") + defer span.End() + span.SetAttributes( + attribute.Int64("round", int64(current.round)), + ) - setRunning.Do(func() { - h.Lock() - h.serving = true - h.Unlock() - }) - - lastBeacon, err := h.chain.Last(h.ctx) - if err != nil { - h.l.Errorw("", "beacon_loop", "loading_last", "err", err) - break - } - h.l.Debugw("", "beacon_loop", "new_round", "round", current.round, "lastbeacon", lastBeacon.Round) - h.broadcastNextPartial(h.ctx, current, lastBeacon) - // if the next round of the last beacon we generated is not the round we - // are now, that means there is a gap between the two rounds. In other - // words, the chain has halted for that amount of rounds or our - // network is not functioning properly. - if lastBeacon.Round+1 < current.round { - // We also launch a sync with the other nodes. If there is one node - // that has a higher beacon, we'll build on it next epoch. If - // nobody has a higher beacon, then this one will be next if the - // network conditions allow for it. - // XXX find a way to start the catchup as soon as the runsync is - // done. Not critical but leads to faster network recovery. - h.l.Debugw("", "beacon_loop", "run_sync_catchup", "last_is", lastBeacon, "should_be", current.round) - h.chain.RunSync(current.round, nil) - } + setRunning.Do(func() { + h.Lock() + h.serving = true + h.Unlock() + }) + + lastBeacon, err := h.chain.Last(ctx) + if err != nil { + span.RecordError(err) + h.l.Errorw("", "beacon_loop", "loading_last", "err", err) + return + } + h.l.Debugw("", "beacon_loop", "new_round", "round", current.round, "lastbeacon", lastBeacon.Round) + h.broadcastNextPartial(ctx, current, lastBeacon) + // if the next round of the last beacon we generated is not the round we + // are now, that means there is a gap between the two rounds. In other + // words, the chain has halted for that amount of rounds or our + // network is not functioning properly. + if lastBeacon.Round+1 < current.round { + // We also launch a sync with the other nodes. If there is one node + // that has a higher beacon, we'll build on it next epoch. If + // nobody has a higher beacon, then this one will be next if the + // network conditions allow for it. + // XXX find a way to start the catchup as soon as the runsync is + // done. Not critical but leads to faster network recovery. + h.l.Debugw("", "beacon_loop", "run_sync_catchup", "last_is", lastBeacon, "should_be", current.round) + h.chain.RunSync(ctx, current.round, nil) + } + }() case b := <-h.chain.AppendedBeaconNoSync(): + ctx, span := metrics.NewSpan(h.ctx, "h.run.appendBeaconNoSync") + span.SetAttributes( + attribute.Int64("round", int64(b.Round)), + ) + h.l.Debugw("", "beacon_loop", "catchupmode", "last_is", b.Round, "current", current.round, "catchup_launch", b.Round < current.round) if b.Round < current.round { // When network is down, all alive nodes will broadcast their @@ -387,6 +447,8 @@ func (h *Handler) run(startTime int64) { // channel will trigger again etc until we arrive at the correct // round. go func(c roundInfo, latest chain.Beacon) { + defer span.End() + h.l.Debugw("sleeping now", "beacon_loop", "catchupmode", "last_is", latest.Round, "sleep_for", h.conf.Group.CatchupPeriod) @@ -394,16 +456,17 @@ func (h *Handler) run(startTime int64) { h.conf.Clock.Sleep(h.conf.Group.CatchupPeriod) select { - case <-h.ctx.Done(): + case <-ctx.Done(): return default: } h.l.Debugw("broadcast next partial", "beacon_loop", "catchupmode", "last_is", latest.Round) - h.broadcastNextPartial(h.ctx, c, &latest) + h.broadcastNextPartial(ctx, c, &latest) }(current, *b) } else if b.Round > current.round { + span.End() h.l.Warnw( "tried catching up, but catchup beacons were newer than the current round", "catchup round", b.Round, @@ -415,6 +478,9 @@ func (h *Handler) run(startTime int64) { } func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, upon *chain.Beacon) { + ctx, span := metrics.NewSpan(ctx, "h.broadcastNextPartial") + defer span.End() + previousSig := upon.Signature round := upon.Round + 1 beaconID := commonutils.GetCanonicalBeaconID(h.conf.Group.ID) @@ -436,6 +502,7 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u currSig, err := h.crypto.SignPartial(msg) if err != nil { + span.RecordError(err) h.l.Fatalw("err creating partial signature", "err", err, "round", round) return } @@ -450,7 +517,7 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u Metadata: metadata, } - h.chain.NewValidPartial(h.addr, packet) + h.chain.NewValidPartial(span.SpanContext(), h.addr, packet) for _, id := range h.crypto.GetGroup().Nodes { select { case <-ctx.Done(): @@ -463,6 +530,9 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u continue } go func(i key.Identity) { + ctx, span := metrics.NewSpan(ctx, "h.broadcastNextPartial.SendTo") + defer span.End() + select { case <-ctx.Done(): return @@ -470,8 +540,14 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u } h.l.Debugw("sending partial", "round", round, "to", i.Address()) + span.SetAttributes( + attribute.Int64("round", int64(round)), + attribute.String("addr", i.Address()), + ) + err := h.client.PartialBeacon(ctx, &i, packet) if err != nil { + span.RecordError(err) h.l.Errorw("error sending partial", "round", round, "err", err, "to", i.Address()) return } @@ -481,7 +557,10 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u // Stop the beacon loop from aggregating further randomness, but it // finishes the one it is aggregating currently. -func (h *Handler) Stop() { +func (h *Handler) Stop(ctx context.Context) { + _, span := metrics.NewSpan(ctx, "h.Stop") + defer span.End() + h.Lock() defer h.Unlock() if h.stopped { @@ -499,7 +578,10 @@ func (h *Handler) Stop() { // StopAt will stop the handler at the given time. It is useful when // transitioning for a resharing. -func (h *Handler) StopAt(stopTime int64) error { +func (h *Handler) StopAt(ctx context.Context, stopTime int64) error { + ctx, span := metrics.NewSpan(ctx, "h.StopAt") + defer span.End() + now := h.conf.Clock.Now().Unix() if stopTime <= now { @@ -510,22 +592,31 @@ func (h *Handler) StopAt(stopTime int64) error { h.l.Debug("stop_at", stopTime, "sleep_for", duration.Seconds()) h.conf.Clock.Sleep(duration) - h.Stop() + h.Stop(ctx) return nil } // AddCallback is a proxy method to register a callback on the backend store -func (h *Handler) AddCallback(id string, fn CallbackFunc) { +func (h *Handler) AddCallback(ctx context.Context, id string, fn CallbackFunc) { + _, span := metrics.NewSpan(ctx, "h.AddCallback") + defer span.End() + h.chain.AddCallback(id, fn) } // RemoveCallback is a proxy method to remove a callback on the backend store -func (h *Handler) RemoveCallback(id string) { +func (h *Handler) RemoveCallback(ctx context.Context, id string) { + _, span := metrics.NewSpan(ctx, "h.RemoveCallback") + defer span.End() + h.chain.RemoveCallback(id) } // GetConfg returns the conf used by the handler -func (h *Handler) GetConfg() *Config { +func (h *Handler) GetConfg(ctx context.Context) *Config { + _, span := metrics.NewSpan(ctx, "h.GetConfg") + defer span.End() + return h.conf } @@ -534,11 +625,17 @@ func (h *Handler) GetConfg() *Config { // were corrupted / invalid / not found in the store. // Note: it does not attempt to correct or fetch these faulty beacons. func (h *Handler) ValidateChain(ctx context.Context, upTo uint64, cb func(r, u uint64)) ([]uint64, error) { + ctx, span := metrics.NewSpan(ctx, "h.ValidateChain") + defer span.End() + return h.chain.ValidateChain(ctx, upTo, cb) } // CorrectChain tells the sync manager to fetch the invalid beacon from its peers. func (h *Handler) CorrectChain(ctx context.Context, faultyBeacons []uint64, peers []net.Peer, cb func(r, u uint64)) error { + ctx, span := metrics.NewSpan(ctx, "h.CorrectChain") + defer span.End() + return h.chain.RunReSync(ctx, faultyBeacons, peers, cb) } diff --git a/chain/beacon/node_test.go b/chain/beacon/node_test.go index a66ab0aae..dc5acb41a 100644 --- a/chain/beacon/node_test.go +++ b/chain/beacon/node_test.go @@ -140,7 +140,7 @@ type BeaconTest struct { scheme *crypto.Scheme } -func NewBeaconTest(t *testing.T, n, thr int, period time.Duration, genesisTime int64, beaconID string) *BeaconTest { +func NewBeaconTest(ctx context.Context, t *testing.T, n, thr int, period time.Duration, genesisTime int64, beaconID string) *BeaconTest { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) prefix := t.TempDir() @@ -169,13 +169,13 @@ func NewBeaconTest(t *testing.T, n, thr int, period time.Duration, genesisTime i } for i := 0; i < n; i++ { - bt.CreateNode(t, i) + bt.CreateNode(ctx, t, i) t.Logf("Creating node %d/%d\n", i+1, n) } return bt } -func (b *BeaconTest) CreateNode(t *testing.T, i int) { +func (b *BeaconTest) CreateNode(ctx context.Context, t *testing.T, i int) { findShare := func(target int) *key.Share { for _, s := range b.shares { if s.Share.I == target { @@ -215,7 +215,7 @@ func (b *BeaconTest) CreateNode(t *testing.T, i int) { Named(knode.Addr). Named(fmt.Sprintf("%d", idx)) version := common.GetAppVersion() - node.handler, err = NewHandler(net.NewGrpcClientWithLogger(l), store, conf, logger, version) + node.handler, err = NewHandler(ctx, net.NewGrpcClientWithLogger(l), store, conf, logger, version) checkErr(err) if node.handler.addr != node.private.Public.Address() { @@ -242,7 +242,7 @@ func (b *BeaconTest) CreateNode(t *testing.T, i int) { } t.Cleanup(func() { t.Log("Stopping node:", idx) - b.StopBeacon(idx) + b.StopBeacon(ctx, idx) t.Log("Node stopped:", idx) }) } @@ -270,9 +270,9 @@ func (b *BeaconTest) ServeBeacon(t *testing.T, i int) { go b.nodes[j].listener.Start() } -func (b *BeaconTest) StartBeacons(t *testing.T, n int) { +func (b *BeaconTest) StartBeacons(ctx context.Context, t *testing.T, n int) { for i := 0; i < n; i++ { - b.StartBeacon(t, i, false) + b.StartBeacon(ctx, t, i, false) } // give time for go routines to kick off @@ -281,14 +281,14 @@ func (b *BeaconTest) StartBeacons(t *testing.T, n int) { require.NoError(t, err) } } -func (b *BeaconTest) StartBeacon(t *testing.T, i int, catchup bool) { +func (b *BeaconTest) StartBeacon(ctx context.Context, t *testing.T, i int, catchup bool) { j := b.searchNode(i) b.nodes[j].started = true if catchup { t.Logf("Start BEACON %s - node pointer %p\n", b.nodes[j].handler.addr, b.nodes[j].handler) - go b.nodes[j].handler.Catchup() + go b.nodes[j].handler.Catchup(ctx) } else { - go b.nodes[j].handler.Start() + go b.nodes[j].handler.Start(ctx) } } @@ -335,14 +335,14 @@ func (b *BeaconTest) MoveTime(t *testing.T, timeToMove time.Duration) { b.time.Advance(timeToMove) } -func (b *BeaconTest) StopBeacon(i int) { +func (b *BeaconTest) StopBeacon(ctx context.Context, i int) { j := b.searchNode(i) if n, ok := b.nodes[j]; ok { if !n.started { return } - n.handler.Stop() - n.listener.Stop(context.Background()) + n.handler.Stop(ctx) + n.listener.Stop(ctx) n.started = false } delete(b.nodes, j) @@ -402,12 +402,13 @@ func TestBeaconSync(t *testing.T) { n := 4 thr := n/2 + 1 period := 2 * time.Second + ctx := context.Background() genesisOffset := 2 * time.Second genesisTime := clock.NewFakeClock().Now().Add(genesisOffset).Unix() beaconID := test.GetBeaconIDFromEnv() - bt := NewBeaconTest(t, n, thr, period, genesisTime, beaconID) + bt := NewBeaconTest(ctx, t, n, thr, period, genesisTime, beaconID) var counter = &sync.WaitGroup{} myCallBack := func(i int) CallbackFunc { @@ -432,12 +433,12 @@ func TestBeaconSync(t *testing.T) { t.Log("serving beacons") for i := 0; i < n; i++ { - bt.CallbackFor(i, myCallBack(i)) + bt.CallbackFor(ctx, i, myCallBack(i)) bt.ServeBeacon(t, i) } t.Log("about to start beacons") - bt.StartBeacons(t, n) + bt.StartBeacons(ctx, t, n) t.Log("all beacons started") // move clock to genesis time @@ -480,6 +481,7 @@ func TestBeaconSync(t *testing.T) { } func TestBeaconSimple(t *testing.T) { + ctx := context.Background() n := 3 thr := n/2 + 1 period := 2 * time.Second @@ -487,7 +489,7 @@ func TestBeaconSimple(t *testing.T) { genesisTime := clock.NewFakeClock().Now().Unix() + 2 beaconID := test.GetBeaconIDFromEnv() - bt := NewBeaconTest(t, n, thr, period, genesisTime, beaconID) + bt := NewBeaconTest(ctx, t, n, thr, period, genesisTime, beaconID) var counter = &sync.WaitGroup{} counter.Add(n) @@ -504,12 +506,12 @@ func TestBeaconSimple(t *testing.T) { } for i := 0; i < n; i++ { - bt.CallbackFor(i, myCallBack) + bt.CallbackFor(ctx, i, myCallBack) // first serve all beacons bt.ServeBeacon(t, i) } - bt.StartBeacons(t, n) + bt.StartBeacons(ctx, t, n) // move clock before genesis time bt.MoveTime(t, 1*time.Second) for i := 0; i < n; i++ { @@ -541,6 +543,7 @@ func TestBeaconSimple(t *testing.T) { } func TestBeaconThreshold(t *testing.T) { + ctx := context.Background() n := 3 thr := n/2 + 1 period := 2 * time.Second @@ -549,7 +552,7 @@ func TestBeaconThreshold(t *testing.T) { genesisTime := clock.NewFakeClock().Now().Add(offsetGenesis).Unix() beaconID := test.GetBeaconIDFromEnv() - bt := NewBeaconTest(t, n, thr, period, genesisTime, beaconID) + bt := NewBeaconTest(ctx, t, n, thr, period, genesisTime, beaconID) currentRound := uint64(0) var counter sync.WaitGroup @@ -591,12 +594,12 @@ func TestBeaconThreshold(t *testing.T) { // open connections for all but one for i := 0; i < n-1; i++ { - bt.CallbackFor(i, myCallBack(i)) + bt.CallbackFor(ctx, i, myCallBack(i)) bt.ServeBeacon(t, i) } // start all but one - bt.StartBeacons(t, n-1) + bt.StartBeacons(ctx, t, n-1) bt.MoveTime(t, bt.period) // move to genesis time and check they ran the round 1 @@ -609,12 +612,12 @@ func TestBeaconThreshold(t *testing.T) { // launch the last one bt.ServeBeacon(t, n-1) - bt.StartBeacon(t, n-1, true) + bt.StartBeacon(ctx, t, n-1, true) t.Log("last node launched!") // 2s because of gRPC default timeouts backoff time.Sleep(2 * time.Second) - bt.CallbackFor(n-1, myCallBack(n-1)) + bt.CallbackFor(ctx, n-1, myCallBack(n-1)) t.Log("make new rounds!") // and then run a few rounds @@ -627,7 +630,8 @@ func TestBeaconThreshold(t *testing.T) { } func TestProcessingPartialBeaconWithNonExistentIndexDoesntSegfault(t *testing.T) { - bt := NewBeaconTest(t, 3, 2, 30*time.Second, 0, "default") + ctx := context.Background() + bt := NewBeaconTest(ctx, t, 3, 2, 30*time.Second, 0, "default") packet := drand.PartialBeaconPacket{ Round: 1, @@ -667,8 +671,8 @@ func (t TestSyncRequest) GetMetadata() *pbCommon.Metadata { return t.metadata } -func (b *BeaconTest) CallbackFor(i int, fn CallbackFunc) { +func (b *BeaconTest) CallbackFor(ctx context.Context, i int, fn CallbackFunc) { j := b.searchNode(i) address := b.nodes[j].private.Public.Address() - b.nodes[j].handler.AddCallback(fmt.Sprintf("%s - node %d", address, i), fn) + b.nodes[j].handler.AddCallback(ctx, fmt.Sprintf("%s - node %d", address, i), fn) } diff --git a/chain/beacon/store.go b/chain/beacon/store.go index 39c9da26f..5b452bacc 100644 --- a/chain/beacon/store.go +++ b/chain/beacon/store.go @@ -38,11 +38,12 @@ type appendStore struct { sync.Mutex } -func newAppendStore(s chain.Store) (chain.Store, error) { - last, err := s.Last(context.Background()) +func newAppendStore(ctx context.Context, s chain.Store) (chain.Store, error) { + last, err := s.Last(ctx) if err != nil { return nil, err } + return &appendStore{ Store: s, last: last, @@ -53,6 +54,9 @@ func newAppendStore(s chain.Store) (chain.Store, error) { var ErrBeaconAlreadyStored = errors.New("beacon value already stored") func (a *appendStore) Put(ctx context.Context, b *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "appendStore.Put") + defer span.End() + a.Lock() defer a.Unlock() @@ -81,8 +85,10 @@ func (a *appendStore) Put(ctx context.Context, b *chain.Beacon) error { return nil } -// schemeStore is a store that run different checks depending on what scheme is being used. -type schemeStore struct { +// SchemeStore is a store that run different checks depending on what scheme is being used. +// +//nolint:gocritic +type SchemeStore struct { chain.Store sch *crypto.Scheme last *chain.Beacon @@ -90,8 +96,8 @@ type schemeStore struct { sync.Mutex } -func NewSchemeStore(s chain.Store, sch *crypto.Scheme) (chain.Store, error) { - last, err := s.Last(context.Background()) +func NewSchemeStore(ctx context.Context, s chain.Store, sch *crypto.Scheme) (chain.Store, error) { + last, err := s.Last(ctx) if err != nil { return nil, err } @@ -103,7 +109,10 @@ func NewSchemeStore(s chain.Store, sch *crypto.Scheme) (chain.Store, error) { }, nil } -func (a *schemeStore) Put(ctx context.Context, b *chain.Beacon) error { +func (a *SchemeStore) Put(ctx context.Context, b *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "schemeStore.Put") + defer span.End() + a.Lock() defer a.Unlock() @@ -149,6 +158,9 @@ func newDiscrepancyStore(s chain.Store, l log.Logger, group *key.Group, cl clock } func (d *discrepancyStore) Put(ctx context.Context, b *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "discrepancyStore.Put") + defer span.End() + // When computing time_discrepancy, time.Now() should be obtained as close as // possible to receiving the beacon, before any other storage layer interaction. // When moved after store.Put(), the value will include the time it takes @@ -212,6 +224,9 @@ func NewCallbackStore(l log.Logger, s chain.Store) CallbackStore { // Put stores a new beacon func (c *callbackStore) Put(ctx context.Context, b *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "callbackStore.Put") + defer span.End() + if err := c.Store.Put(ctx, b); err != nil { return err } @@ -267,9 +282,9 @@ func (c *callbackStore) RemoveCallback(id string) { } } -func (c *callbackStore) Close(ctx context.Context) error { +func (c *callbackStore) Close() error { close(c.stopping) - return c.Store.Close(ctx) + return c.Store.Close() } func (c *callbackStore) runWorker(jobChan chan cbPair) { diff --git a/chain/beacon/store_test.go b/chain/beacon/store_test.go index 38c137c6e..482f6bc12 100644 --- a/chain/beacon/store_test.go +++ b/chain/beacon/store_test.go @@ -26,7 +26,7 @@ func TestSchemeStore(t *testing.T) { err = bstore.Put(ctx, genesisBeacon) require.NoError(t, err) - ss, err := NewSchemeStore(bstore, sch) + ss, err := NewSchemeStore(ctx, bstore, sch) require.NoError(t, err) newBeacon := &chain.Beacon{ diff --git a/chain/beacon/sync_manager.go b/chain/beacon/sync_manager.go index cf02b252e..fb86dd2d4 100644 --- a/chain/beacon/sync_manager.go +++ b/chain/beacon/sync_manager.go @@ -6,10 +6,11 @@ import ( "fmt" "math/rand" "strings" - "sync" "time" cl "github.com/jonboulle/clockwork" + "go.opentelemetry.io/otel/attribute" + oteltrace "go.opentelemetry.io/otel/trace" "github.com/drand/drand/chain" chainerrors "github.com/drand/drand/chain/errors" @@ -17,6 +18,7 @@ import ( "github.com/drand/drand/crypto" dcontext "github.com/drand/drand/internal/context" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/common" proto "github.com/drand/drand/protobuf/drand" @@ -26,9 +28,11 @@ import ( // cancellation of sync requests if not progressing, performs rate limiting of // sync requests. type SyncManager struct { - log log.Logger - clock cl.Clock - store chain.Store + ctx context.Context + ctxCancel context.CancelFunc + log log.Logger + clock cl.Clock + store chain.Store // insecureStore will store beacons without doing any checks insecureStore chain.Store info *chain.Info @@ -43,8 +47,6 @@ type SyncManager struct { newReq chan RequestInfo // updated with each new beacon we receive from sync newSync chan *chain.Beacon - done chan bool - mu sync.Mutex // we need to know our current daemon address nodeAddr string } @@ -70,13 +72,17 @@ type SyncConfig struct { // NewSyncManager returns a sync manager that will use the given store to store // newly synced beacon. -func NewSyncManager(c *SyncConfig) (*SyncManager, error) { +func NewSyncManager(ctx context.Context, c *SyncConfig) (*SyncManager, error) { sch, err := crypto.SchemeFromName(c.Info.GetSchemeName()) if err != nil { return nil, err } + ctx, ctxCancel := context.WithCancel(ctx) + return &SyncManager{ + ctx: ctx, + ctxCancel: ctxCancel, log: c.Log.Named("SyncManager"), clock: c.Clock, store: c.Store, @@ -89,17 +95,16 @@ func NewSyncManager(c *SyncConfig) (*SyncManager, error) { factor: syncExpiryFactor, newReq: make(chan RequestInfo, syncQueueRequest), newSync: make(chan *chain.Beacon, 1), - done: make(chan bool, 1), }, nil } func (s *SyncManager) Stop() { - s.mu.Lock() - defer s.mu.Unlock() - close(s.done) + s.ctxCancel() } type RequestInfo struct { + spanContext oteltrace.SpanContext + nodes []net.Peer from uint64 upTo uint64 @@ -109,12 +114,17 @@ type RequestInfo struct { // round. Depending on the current state of the syncing process, there might not // be a new process starting (for example if we already have the round // requested). upTo == 0 means the syncing process goes on forever. -func (s *SyncManager) SendSyncRequest(upTo uint64, nodes []net.Peer) { - s.newReq <- NewRequestInfo(upTo, nodes) +func (s *SyncManager) SendSyncRequest(spanContext oteltrace.SpanContext, upTo uint64, nodes []net.Peer) { + s.newReq <- NewRequestInfo(spanContext, upTo, nodes) } -func NewRequestInfo(upTo uint64, nodes []net.Peer) RequestInfo { - return RequestInfo{upTo: upTo, nodes: nodes} +func NewRequestInfo(spanContext oteltrace.SpanContext, upTo uint64, nodes []net.Peer) RequestInfo { + return RequestInfo{ + spanContext: spanContext, + + upTo: upTo, + nodes: nodes, + } } // Run handles non-blocking sync requests coming from the regular operation of the daemon @@ -126,22 +136,26 @@ func (s *SyncManager) Run() { // tracks the time of the last round we successfully synced lastRoundTime := 0 // the context being used by the current sync process - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(s.ctx) for { select { - case <-s.done: + case <-s.ctx.Done(): s.log.Infow("", "sync_manager", "exits") cancel() return case request := <-s.newReq: + _, span := metrics.NewSpanFromSpanContext(ctx, request.spanContext, "syncManager.AddCallback") + // check if the request is still valid last, err := s.store.Last(ctx) if err != nil { + span.End() s.log.Debugw("unable to fetch from store", "sync_manager", "store.Last", "err", err) continue } // do we really need a sync request ? if request.upTo > 0 && last.Round >= request.upTo { + span.End() s.log.Debugw("request already filled", "sync_manager", "skipping_request", "last", last.Round, "request", request.upTo) continue } @@ -153,10 +167,11 @@ func (s *SyncManager) Run() { // must have gotten some data. upperBound := lastRoundTime + int(s.period.Seconds())*s.factor if upperBound < int(s.clock.Now().Unix()) { + span.End() // we haven't received a new block in a while // -> time to start a new sync cancel() - ctx, cancel = context.WithCancel(context.Background()) + ctx, cancel = context.WithCancel(s.ctx) //nolint go s.Sync(ctx, request) } @@ -168,6 +183,9 @@ func (s *SyncManager) Run() { } func (s *SyncManager) CheckPastBeacons(ctx context.Context, upTo uint64, cb func(r, u uint64)) ([]uint64, error) { + _, span := metrics.NewSpan(ctx, "syncManager.CheckPastBeacons") + defer span.End() + logger := s.log.Named("pastBeaconCheck") logger.Debugw("Starting to check past beacons", "upTo", upTo) @@ -235,6 +253,9 @@ func (s *SyncManager) CheckPastBeacons(ctx context.Context, upTo uint64, cb func } func (s *SyncManager) CorrectPastBeacons(ctx context.Context, faultyBeacons []uint64, peers []net.Peer, cb func(r, u uint64)) error { + _, span := metrics.NewSpan(ctx, "syncManager.CorrectPastBeacons") + defer span.End() + target := uint64(len(faultyBeacons)) if target == 0 { return nil @@ -269,6 +290,9 @@ func (s *SyncManager) CorrectPastBeacons(ctx context.Context, faultyBeacons []ui // ReSync handles resyncs that where necessarily launched by a CLI. func (s *SyncManager) ReSync(ctx context.Context, from, to uint64, nodes []net.Peer) error { + ctx, span := metrics.NewSpan(ctx, "syncManager.ReSync") + defer span.End() + s.log.Debugw("Launching re-sync request", "from", from, "upTo", to) if from == 0 { @@ -278,6 +302,8 @@ func (s *SyncManager) ReSync(ctx context.Context, from, to uint64, nodes []net.P // we always do it and we block while doing it if it's a resync. Notice that the regular sync will // keep running in the background in their own go routine. err := s.Sync(ctx, RequestInfo{ + spanContext: span.SpanContext(), + nodes: nodes, from: from, upTo: to, @@ -286,6 +312,8 @@ func (s *SyncManager) ReSync(ctx context.Context, from, to uint64, nodes []net.P if errors.Is(err, ErrFailedAll) { s.log.Warnw("All node have failed resync once, retrying one time") err = s.Sync(ctx, RequestInfo{ + spanContext: span.SpanContext(), + nodes: nodes, from: from, upTo: to, @@ -296,7 +324,12 @@ func (s *SyncManager) ReSync(ctx context.Context, from, to uint64, nodes []net.P } // Sync will launch the requested sync with the requested peers and returns once done, even if it failed +// +//nolint:gocritic // Request size is correct, no need for a pointer. func (s *SyncManager) Sync(ctx context.Context, request RequestInfo) error { + ctx, span := metrics.NewSpanFromSpanContext(ctx, request.spanContext, "syncManager.Sync") + defer span.End() + s.log.Debugw("starting new sync", "sync_manager", "start sync", "up_to", request.upTo, "nodes", peersToString(request.nodes)) // shuffle through the nodes for _, n := range rand.Perm(len(request.nodes)) { @@ -328,6 +361,15 @@ func (s *SyncManager) Sync(ctx context.Context, request RequestInfo) error { // //nolint:gocyclo,funlen func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer net.Peer) bool { + global, span := metrics.NewSpan(global, "dd.LoadBeaconFromStore") + defer span.End() + + span.SetAttributes( + attribute.Int64("fromRound", int64(from)), + attribute.Int64("upToRound", int64(upTo)), + attribute.String("addr", peer.Address()), + ) + logger := s.log.Named("tryNode") // we put a cancel to still keep the global context open but stop with this @@ -340,6 +382,7 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne last, err := s.store.Last(cnode) if err != nil { + span.RecordError(err) logger.Errorw("unable to fetch from store", "sync_manager", "store.Last", "err", err) return false } @@ -347,6 +390,7 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne if from == 0 { from = last.Round + 1 } else if from > upTo { + span.RecordError(fmt.Errorf("invalid request from %d upTo %d", from, upTo)) logger.Errorw("Invalid request: from > upTo", "from", from, "upTo", upTo) return false } @@ -358,6 +402,7 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne beaconCh, err := s.client.SyncChain(cnode, peer, req) if err != nil { + span.RecordError(errors.New("unable_to_sync")) logger.Errorw("unable_to_sync", "with_peer", peer.Address(), "err", err) return false } @@ -376,15 +421,20 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne for { select { case beaconPacket, ok := <-beaconCh: + cnode, span := metrics.NewSpan(cnode, "dd.LoadBeaconFromStore") + if !ok { logger.Debugw("SyncChain channel closed", "with_peer", peer.Address()) + span.End() return false } // Check if we got the right packet metadata := beaconPacket.GetMetadata() if metadata != nil && metadata.BeaconID != s.info.ID { + span.RecordError(errors.New("wrong beaconID")) logger.Errorw("wrong beaconID", "expected", s.info.ID, "got", metadata.BeaconID) + span.End() return false } @@ -404,24 +454,31 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne // verify the signature validity if err := s.scheme.VerifyBeacon(beacon, s.info.PublicKey); err != nil { + span.RecordError(errors.New("invalid beacon")) logger.Debugw("Invalid_beacon", "from_peer", peer.Address(), "round", beacon.Round, "err", err, "beacon", fmt.Sprintf("%+v", beacon)) + span.End() return false } if isResync { logger.Debugw("Resync Put: trying to save beacon", "beacon", beacon.Round) if err := s.insecureStore.Put(cnode, beacon); err != nil { + span.RecordError(err) logger.Errorw("Resync Put: unable to save", "with_peer", peer.Address(), "err", err) + span.End() return false } } else { if err := s.store.Put(cnode, beacon); err != nil { + span.RecordError(err) if errors.Is(err, ErrBeaconAlreadyStored) { logger.Debugw("Put: race with aggregation", "with_peer", peer.Address(), "err", err) + span.End() return beacon.Round == upTo } logger.Errorw("Put: unable to save", "with_peer", peer.Address(), "err", err) + span.End() return false } } @@ -432,9 +489,11 @@ func (s *SyncManager) tryNode(global context.Context, from, upTo uint64, peer ne last = beacon if last.Round == upTo { logger.Debugw("sync_manager finished syncing up to", "round", upTo) + span.End() return true } // else, we keep waiting for the next beacons + span.End() case <-cnode.Done(): // if global is Done, then so is cnode // it can be the remote note that stopped the syncing or a network error with it @@ -466,8 +525,10 @@ var ErrCallbackReplaced = errors.New("callback replaced") // //nolint:funlen,gocyclo // This has the right length func SyncChain(l log.Logger, store CallbackStore, req SyncRequest, stream SyncStream) error { + ctx, span := metrics.NewSpan(stream.Context(), "SyncChain") + defer span.End() + fromRound := req.GetFromRound() - ctx := stream.Context() addr := net.RemoteAddress(ctx) id := addr + "SyncChain" @@ -483,6 +544,7 @@ func SyncChain(l log.Logger, store CallbackStore, req SyncRequest, stream SyncSt } if last.Round < fromRound { + span.RecordError(chainerrors.ErrNoBeaconStored) return fmt.Errorf("%w %d < %d", chainerrors.ErrNoBeaconStored, last.Round, fromRound) } @@ -492,6 +554,7 @@ func SyncChain(l log.Logger, store CallbackStore, req SyncRequest, stream SyncSt return ctx.Err() default: } + packet := beaconToProto(b, beaconID) err := stream.Send(packet) if err != nil { diff --git a/chain/boltdb/store.go b/chain/boltdb/store.go index 4a57c33ac..5165a1179 100644 --- a/chain/boltdb/store.go +++ b/chain/boltdb/store.go @@ -14,6 +14,7 @@ import ( "github.com/drand/drand/chain" chainerrors "github.com/drand/drand/chain/errors" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" ) // BoltStore implements the Store interface using the kv storage boltdb (native @@ -51,6 +52,9 @@ func isThisATest(ctx context.Context) bool { // NewBoltStore returns a Store implementation using the boltdb storage engine. func NewBoltStore(ctx context.Context, l log.Logger, folder string, opts *bolt.Options) (chain.Store, error) { + ctx, span := metrics.NewSpan(ctx, "boltStore.NewBoltStore") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -80,6 +84,9 @@ func NewBoltStore(ctx context.Context, l log.Logger, folder string, opts *bolt.O } func shouldUseTrimmedBolt(ctx context.Context, l log.Logger, sourceBeaconPath string, opts *bolt.Options) bool { + ctx, span := metrics.NewSpan(ctx, "boltStore.shouldUseTrimmedBolt") + defer span.End() + if isThisATest(ctx) { return false } @@ -110,7 +117,12 @@ func shouldUseTrimmedBolt(ctx context.Context, l log.Logger, sourceBeaconPath st } // Len performs a big scan over the bucket and is _very_ slow - use sparingly! +// +//nolint:dupl // This is a method of a separate type func (b *BoltStore) Len(ctx context.Context) (int, error) { + ctx, span := metrics.NewSpan(ctx, "boltStore.Len") + defer span.End() + select { case <-ctx.Done(): return 0, ctx.Err() @@ -130,7 +142,7 @@ func (b *BoltStore) Len(ctx context.Context) (int, error) { return length, err } -func (b *BoltStore) Close(context.Context) error { +func (b *BoltStore) Close() error { err := b.db.Close() if err != nil { b.log.Errorw("", "boltdb", "close", "err", err) @@ -141,6 +153,9 @@ func (b *BoltStore) Close(context.Context) error { // Put implements the Store interface. WARNING: It does NOT verify that this // beacon is not already saved in the database or not and will overwrite it. func (b *BoltStore) Put(ctx context.Context, beacon *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "boltStore.Put") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -170,6 +185,9 @@ func (b *BoltStore) Put(ctx context.Context, beacon *chain.Beacon) error { // Last returns the last beacon signature saved into the db func (b *BoltStore) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltStore.Last") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -191,6 +209,9 @@ func (b *BoltStore) Last(ctx context.Context) (*chain.Beacon, error) { // Get returns the beacon saved at this round func (b *BoltStore) Get(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltStore.Get") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -210,6 +231,9 @@ func (b *BoltStore) Get(ctx context.Context, round uint64) (*chain.Beacon, error } func (b *BoltStore) Del(ctx context.Context, round uint64) error { + ctx, span := metrics.NewSpan(ctx, "boltStore.Del") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -223,6 +247,9 @@ func (b *BoltStore) Del(ctx context.Context, round uint64) error { } func (b *BoltStore) Cursor(ctx context.Context, fn func(context.Context, chain.Cursor) error) error { + ctx, span := metrics.NewSpan(ctx, "boltStore.Cursor") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -246,6 +273,9 @@ func (b *BoltStore) Cursor(ctx context.Context, fn func(context.Context, chain.C // SaveTo saves the bolt database to an alternate file. func (b *BoltStore) SaveTo(ctx context.Context, w io.Writer) error { + ctx, span := metrics.NewSpan(ctx, "boltStore.SaveTo") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -263,6 +293,9 @@ type boltCursor struct { } func (c *boltCursor) First(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltCursor.First") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -281,6 +314,9 @@ func (c *boltCursor) First(ctx context.Context) (*chain.Beacon, error) { // Next returns the next value in the database for the given cursor. // When reaching the end of the database, it emits the ErrNoBeaconStored error to flag that it finished the iteration. func (c *boltCursor) Next(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltCursor.Next") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -297,6 +333,9 @@ func (c *boltCursor) Next(ctx context.Context) (*chain.Beacon, error) { } func (c *boltCursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltCursor.Seek") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -313,6 +352,9 @@ func (c *boltCursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, err } func (c *boltCursor) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltCursor.Last") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() diff --git a/chain/boltdb/store_test.go b/chain/boltdb/store_test.go index 27e3fa869..e7b4f611c 100644 --- a/chain/boltdb/store_test.go +++ b/chain/boltdb/store_test.go @@ -19,7 +19,7 @@ func TestStoreBoltOrder(t *testing.T) { store, err := NewBoltStore(ctx, l, tmp, nil) require.NoError(t, err) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() b1 := &chain.Beacon{ @@ -53,8 +53,8 @@ func TestStoreBoltOrder(t *testing.T) { } func TestStoreBolt(t *testing.T) { - tmp := t.TempDir() ctx := IsATest(context.Background()) + tmp := t.TempDir() l := testlogger.New(t) var sig1 = []byte{0x01, 0x02, 0x03} @@ -98,7 +98,7 @@ func TestStoreBolt(t *testing.T) { require.NoError(t, err) require.Equal(t, b2, received) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) store, err = NewBoltStore(ctx, l, tmp, nil) @@ -109,7 +109,7 @@ func TestStoreBolt(t *testing.T) { bb1, err := store.Get(ctx, b1.Round) require.NoError(t, err) require.Equal(t, b1, bb1) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) store, err = NewBoltStore(ctx, l, tmp, nil) @@ -161,7 +161,7 @@ func TestStore_Cursor(t *testing.T) { dbStore, err := NewBoltStore(ctx, l, tmp, nil) require.NoError(t, err) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() sigs := map[int][]byte{ diff --git a/chain/boltdb/trimmed.go b/chain/boltdb/trimmed.go index 79b9994d6..b16ba5421 100644 --- a/chain/boltdb/trimmed.go +++ b/chain/boltdb/trimmed.go @@ -12,6 +12,7 @@ import ( "github.com/drand/drand/chain" chainerrors "github.com/drand/drand/chain/errors" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" ) // trimmedStore implements the Store interface using the kv storage boltdb (native @@ -28,6 +29,9 @@ type trimmedStore struct { // newTrimmedStore returns a Store implementation using the boltdb storage engine. func newTrimmedStore(ctx context.Context, l log.Logger, folder string, opts *bolt.Options) (*trimmedStore, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.NewTrimmedStore") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -54,7 +58,12 @@ func newTrimmedStore(ctx context.Context, l log.Logger, folder string, opts *bol } // Len performs a big scan over the bucket and is _very_ slow - use sparingly! +// +//nolint:dupl // This is a function on a separate type. func (b *trimmedStore) Len(ctx context.Context) (int, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Len") + defer span.End() + select { case <-ctx.Done(): return 0, ctx.Err() @@ -74,7 +83,7 @@ func (b *trimmedStore) Len(ctx context.Context) (int, error) { return length, err } -func (b *trimmedStore) Close(context.Context) error { +func (b *trimmedStore) Close() error { err := b.db.Close() if err != nil { b.log.Errorw("", "boltdb", "close", "err", err) @@ -85,6 +94,9 @@ func (b *trimmedStore) Close(context.Context) error { // Put implements the Store interface. WARNING: It does NOT verify that this // beacon is not already saved in the database or not and will overwrite it. func (b *trimmedStore) Put(ctx context.Context, beacon *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Put") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -108,6 +120,9 @@ func (b *trimmedStore) Put(ctx context.Context, beacon *chain.Beacon) error { // Last returns the last beacon signature saved into the db func (b *trimmedStore) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Last") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -133,6 +148,9 @@ func (b *trimmedStore) Last(ctx context.Context) (*chain.Beacon, error) { // Get returns the beacon saved at this round func (b *trimmedStore) Get(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Get") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -193,6 +211,9 @@ func (b *trimmedStore) getBeacon(ctx context.Context, bucket *bolt.Bucket, round } func (b *trimmedStore) Del(ctx context.Context, round uint64) error { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Del") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -206,6 +227,9 @@ func (b *trimmedStore) Del(ctx context.Context, round uint64) error { } func (b *trimmedStore) Cursor(ctx context.Context, fn func(context.Context, chain.Cursor) error) error { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Cursor") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -228,7 +252,10 @@ func (b *trimmedStore) Cursor(ctx context.Context, fn func(context.Context, chai } // SaveTo saves the bolt database to an alternate file. -func (b *trimmedStore) SaveTo(_ context.Context, w io.Writer) error { +func (b *trimmedStore) SaveTo(ctx context.Context, w io.Writer) error { + _, span := metrics.NewSpan(ctx, "boltTrimmedStore.SaveTo") + defer span.End() + return b.db.View(func(tx *bolt.Tx) error { _, err := tx.WriteTo(w) return err @@ -241,16 +268,25 @@ type trimmedBoltCursor struct { } func (c *trimmedBoltCursor) First(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Cursor.First") + defer span.End() + return c.store.getCursorBeacon(ctx, c.Bucket(), c.Cursor.First) } // Next returns the next value in the database for the given cursor. // When reaching the end of the database, it emits the ErrNoBeaconStored error to flag that it finished the iteration. func (c *trimmedBoltCursor) Next(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Cursor.Next") + defer span.End() + return c.store.getCursorBeacon(ctx, c.Bucket(), c.Cursor.Next) } func (c *trimmedBoltCursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Cursor.Seek") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -281,6 +317,9 @@ func (c *trimmedBoltCursor) Seek(ctx context.Context, round uint64) (*chain.Beac } func (c *trimmedBoltCursor) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "boltTrimmedStore.Cursor.Last") + defer span.End() + return c.store.getCursorBeacon(ctx, c.Bucket(), c.Cursor.Last) } diff --git a/chain/boltdb/trimmed_test.go b/chain/boltdb/trimmed_test.go index 2a5ed3617..231e918b6 100644 --- a/chain/boltdb/trimmed_test.go +++ b/chain/boltdb/trimmed_test.go @@ -35,7 +35,7 @@ func TestTrimmedStoreBoltOrder(t *testing.T) { store, err := newTrimmedStore(ctx, l, tmp, nil) require.NoError(t, err) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() b0 := &chain.Beacon{ @@ -141,7 +141,7 @@ func TestTrimmedStoreBolt(t *testing.T) { require.NoError(t, err) require.Equal(t, b2, received) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) store, err = newTrimmedStore(ctx, l, tmp, nil) @@ -152,7 +152,7 @@ func TestTrimmedStoreBolt(t *testing.T) { bb1, err := store.Get(ctx, b1.Round) require.NoError(t, err) require.Equal(t, b1, bb1) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) store, err = newTrimmedStore(ctx, l, tmp, nil) @@ -206,7 +206,7 @@ func TestTrimmedStore_Cursor(t *testing.T) { dbStore, err := newTrimmedStore(ctx, l, tmp, nil) require.NoError(t, err) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() sigs := map[int][]byte{ diff --git a/chain/memdb/store.go b/chain/memdb/store.go index f385dcc46..03def195e 100644 --- a/chain/memdb/store.go +++ b/chain/memdb/store.go @@ -9,6 +9,7 @@ import ( "github.com/drand/drand/chain" "github.com/drand/drand/chain/errors" + "github.com/drand/drand/metrics" ) // Store represents access to the in-memory storage for beacon management. @@ -33,14 +34,20 @@ func NewStore(bufferSize int) *Store { } } -func (s *Store) Len(_ context.Context) (int, error) { +func (s *Store) Len(ctx context.Context) (int, error) { + _, span := metrics.NewSpan(ctx, "memDB.Len") + defer span.End() + s.storeMtx.RLock() defer s.storeMtx.RUnlock() return len(s.store), nil } -func (s *Store) Put(_ context.Context, beacon *chain.Beacon) error { +func (s *Store) Put(ctx context.Context, beacon *chain.Beacon) error { + _, span := metrics.NewSpan(ctx, "memDB.Put") + defer span.End() + s.storeMtx.Lock() defer s.storeMtx.Unlock() defer func() { @@ -70,7 +77,10 @@ func (s *Store) Put(_ context.Context, beacon *chain.Beacon) error { return nil } -func (s *Store) Last(_ context.Context) (*chain.Beacon, error) { +func (s *Store) Last(ctx context.Context) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Last") + defer span.End() + s.storeMtx.RLock() defer s.storeMtx.RUnlock() @@ -82,7 +92,10 @@ func (s *Store) Last(_ context.Context) (*chain.Beacon, error) { return result, nil } -func (s *Store) Get(_ context.Context, round uint64) (*chain.Beacon, error) { +func (s *Store) Get(ctx context.Context, round uint64) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Get") + defer span.End() + s.storeMtx.RLock() defer s.storeMtx.RUnlock() @@ -96,6 +109,9 @@ func (s *Store) Get(_ context.Context, round uint64) (*chain.Beacon, error) { } func (s *Store) Cursor(ctx context.Context, f func(context.Context, chain.Cursor) error) error { + ctx, span := metrics.NewSpan(ctx, "memDB.Cursor") + defer span.End() + cursor := &memDBCursor{ s: s, } @@ -103,11 +119,14 @@ func (s *Store) Cursor(ctx context.Context, f func(context.Context, chain.Cursor } // Close is a noop -func (s *Store) Close(_ context.Context) error { +func (s *Store) Close() error { return nil } -func (s *Store) Del(_ context.Context, round uint64) error { +func (s *Store) Del(ctx context.Context, round uint64) error { + _, span := metrics.NewSpan(ctx, "memDB.Del") + defer span.End() + s.storeMtx.Lock() defer s.storeMtx.Unlock() @@ -128,9 +147,12 @@ func (s *Store) Del(_ context.Context, round uint64) error { return nil } -func (s *Store) SaveTo(ctx context.Context, w io.Writer) error { +func (s *Store) SaveTo(ctx context.Context, _ io.Writer) error { + _, span := metrics.NewSpan(ctx, "memDB.SaveTo") + defer span.End() + // TODO implement me - panic("implement me") + return fmt.Errorf("saveTo not implemented for MemDB Store") } type memDBCursor struct { @@ -138,7 +160,10 @@ type memDBCursor struct { pos int } -func (m *memDBCursor) First(_ context.Context) (*chain.Beacon, error) { +func (m *memDBCursor) First(ctx context.Context) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Cursor.First") + defer span.End() + m.s.storeMtx.RLock() defer m.s.storeMtx.RUnlock() @@ -151,7 +176,10 @@ func (m *memDBCursor) First(_ context.Context) (*chain.Beacon, error) { return result, nil } -func (m *memDBCursor) Next(_ context.Context) (*chain.Beacon, error) { +func (m *memDBCursor) Next(ctx context.Context) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Cursor.Next") + defer span.End() + m.s.storeMtx.RLock() defer m.s.storeMtx.RUnlock() @@ -168,7 +196,10 @@ func (m *memDBCursor) Next(_ context.Context) (*chain.Beacon, error) { return result, nil } -func (m *memDBCursor) Seek(_ context.Context, round uint64) (*chain.Beacon, error) { +func (m *memDBCursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Cursor.Seek") + defer span.End() + m.s.storeMtx.RLock() defer m.s.storeMtx.RUnlock() @@ -184,7 +215,10 @@ func (m *memDBCursor) Seek(_ context.Context, round uint64) (*chain.Beacon, erro return nil, errors.ErrNoBeaconStored } -func (m *memDBCursor) Last(_ context.Context) (*chain.Beacon, error) { +func (m *memDBCursor) Last(ctx context.Context) (*chain.Beacon, error) { + _, span := metrics.NewSpan(ctx, "memDB.Cursor.Last") + defer span.End() + m.s.storeMtx.RLock() defer m.s.storeMtx.RUnlock() diff --git a/chain/memdb/store_test.go b/chain/memdb/store_test.go index 3dfcd5b1b..dcd535f8a 100644 --- a/chain/memdb/store_test.go +++ b/chain/memdb/store_test.go @@ -21,7 +21,7 @@ func TestStoreBoltOrder(t *testing.T) { store := memdb.NewStore(10) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() b1 := &chain.Beacon{ @@ -97,7 +97,7 @@ func TestStoreBolt(t *testing.T) { require.NoError(t, err) require.Equal(t, b2, received) - err = s.Close(ctx) + err = s.Close() require.NoError(t, err) s = memdb.NewStore(10) @@ -107,7 +107,7 @@ func TestStoreBolt(t *testing.T) { bb1, err := s.Get(ctx, b1.Round) require.NoError(t, err) require.Equal(t, b1, bb1) - err = s.Close(ctx) + err = s.Close() require.NoError(t, err) s = memdb.NewStore(10) @@ -156,7 +156,7 @@ func TestStore_Cursor(t *testing.T) { dbStore := memdb.NewStore(10) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() sigs := map[int][]byte{ diff --git a/chain/postgresdb/database/database.go b/chain/postgresdb/database/database.go index 2703b7380..7d0bea457 100644 --- a/chain/postgresdb/database/database.go +++ b/chain/postgresdb/database/database.go @@ -15,6 +15,7 @@ import ( _ "github.com/lib/pq" // Calls init function. "github.com/drand/drand/log" + "github.com/drand/drand/metrics" ) // Config is the required properties to use the database. @@ -102,6 +103,9 @@ func ConfigFromDSN(dsn string) (Config, error) { // //nolint:gocritic // There is nothing wrong with using value semantics here. func Open(ctx context.Context, cfg Config) (*sqlx.DB, error) { + ctx, span := metrics.NewSpan(ctx, "database.Open") + defer span.End() + sslMode := "require" if cfg.DisableTLS { sslMode = "disable" @@ -133,6 +137,9 @@ func Open(ctx context.Context, cfg Config) (*sqlx.DB, error) { // StatusCheck returns nil if it can successfully talk to the database. It // returns a non-nil error otherwise. func StatusCheck(ctx context.Context, db *sqlx.DB) error { + ctx, span := metrics.NewSpan(ctx, "database.StatusCheck") + defer span.End() + var pingError error //nolint:gomnd // We want to have a reasonable retry period @@ -143,7 +150,7 @@ check: for { select { case <-t.C: - pingError = db.Ping() + pingError = db.PingContext(ctx) if pingError == nil { break check } @@ -158,7 +165,10 @@ check: } // WithinTran runs passed function and do commit/rollback at the end. -func WithinTran(l log.Logger, db *sqlx.DB, fn func(*sqlx.Tx) error) error { +func WithinTran(ctx context.Context, l log.Logger, db *sqlx.DB, fn func(context.Context, *sqlx.Tx) error) error { + ctx, span := metrics.NewSpan(ctx, "database.WithinTran") + defer span.End() + l.Infow("begin tran") tx, err := db.Beginx() if err != nil { @@ -175,7 +185,7 @@ func WithinTran(l log.Logger, db *sqlx.DB, fn func(*sqlx.Tx) error) error { l.Infow("rollback tran") }() - if err := fn(tx); err != nil { + if err := fn(ctx, tx); err != nil { return fmt.Errorf("exec tran: %w", err) } diff --git a/chain/postgresdb/pgdb/pgdb.go b/chain/postgresdb/pgdb/pgdb.go index c2779f474..8e8a997e8 100644 --- a/chain/postgresdb/pgdb/pgdb.go +++ b/chain/postgresdb/pgdb/pgdb.go @@ -12,6 +12,7 @@ import ( "github.com/drand/drand/chain" chainerrors "github.com/drand/drand/chain/errors" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" ) // Store represents access to the postgres database for beacon management. @@ -25,6 +26,9 @@ type Store struct { // NewStore returns a new store that provides the CRUD based API needed for // supporting drand serialization. func NewStore(ctx context.Context, l log.Logger, db *sqlx.DB, beaconName string) (*Store, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.NewStore") + defer span.End() + p := Store{ log: l, db: db, @@ -43,12 +47,15 @@ func NewStore(ctx context.Context, l log.Logger, db *sqlx.DB, beaconName string) } // Close is an noop. -func (p *Store) Close(context.Context) error { +func (p *Store) Close() error { return nil } // AddBeaconID adds the beacon to the database if it does not exist. func (p *Store) AddBeaconID(ctx context.Context, beaconName string) (int, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.AddBeaconID") + defer span.End() + select { case <-ctx.Done(): return 0, ctx.Err() @@ -98,6 +105,9 @@ func (p *Store) AddBeaconID(ctx context.Context, beaconName string) (int, error) // Len returns the number of beacons in the configured beacon table. func (p *Store) Len(ctx context.Context) (int, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Len") + defer span.End() + select { case <-ctx.Done(): return 0, ctx.Err() @@ -137,6 +147,9 @@ func (p *Store) Len(ctx context.Context) (int, error) { // Put adds the specified beacon to the database. func (p *Store) Put(ctx context.Context, b *chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.Put") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -167,6 +180,9 @@ func (p *Store) Put(ctx context.Context, b *chain.Beacon) error { // BatchPut is useful if you want to write a lot of beacons to the database at once. func (p *Store) BatchPut(ctx context.Context, bs []chain.Beacon) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.BatchLen") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -212,6 +228,9 @@ func (p *Store) BatchPut(ctx context.Context, bs []chain.Beacon) error { // Last returns the last beacon stored in the configured beacon table. func (p *Store) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Last") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -241,6 +260,9 @@ func (p *Store) Last(ctx context.Context) (*chain.Beacon, error) { // Get returns the specified beacon from the configured beacon table. func (p *Store) Get(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Get") + defer span.End() + return p.get(ctx, round, true) } @@ -275,6 +297,9 @@ func (p *Store) get(ctx context.Context, round uint64, canFetchPrevious bool) (* // Del removes the specified round from the beacon table. func (p *Store) Del(ctx context.Context, round uint64) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.Del") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -302,6 +327,9 @@ func (p *Store) Del(ctx context.Context, round uint64) error { // Cursor returns a cursor for iterating over the beacon table. func (p *Store) Cursor(ctx context.Context, fn func(context.Context, chain.Cursor) error) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -317,13 +345,19 @@ func (p *Store) Cursor(ctx context.Context, fn func(context.Context, chain.Curso } // SaveTo does something and I am not sure just yet. -func (p *Store) SaveTo(context.Context, io.Writer) error { +func (p *Store) SaveTo(ctx context.Context, _ io.Writer) error { + _, span := metrics.NewSpan(ctx, "pgStore.SaveTo") + defer span.End() + return fmt.Errorf("saveTo not implemented for Postgres Store") } // DropFK is used to optimize the calls to Store.BatchPut and should be called before it. // It drops the relation between beacons and beacon_details tables. func (p *Store) DropFK(ctx context.Context) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.DropFK") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -340,6 +374,9 @@ func (p *Store) DropFK(ctx context.Context) error { // AddFK reconstructs the relation between beacons and beacon_details tables after Store.DropFK was called. func (p *Store) AddFK(ctx context.Context) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.AddFK") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() @@ -364,6 +401,9 @@ type cursor struct { // First returns the first beacon from the configured beacon table. func (c *cursor) First(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor.First") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -396,6 +436,9 @@ func (c *cursor) First(ctx context.Context) (*chain.Beacon, error) { // Next returns the next beacon from the configured beacon table. func (c *cursor) Next(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor.Next") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -431,6 +474,9 @@ func (c *cursor) Next(ctx context.Context) (*chain.Beacon, error) { // Seek searches the beacon table for the specified round func (c *cursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor.Seek") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -467,6 +513,9 @@ func (c *cursor) Seek(ctx context.Context, round uint64) (*chain.Beacon, error) // Last returns the last beacon from the configured beacon table. func (c *cursor) Last(ctx context.Context) (*chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor.Last") + defer span.End() + select { case <-ctx.Done(): return nil, ctx.Err() @@ -502,6 +551,9 @@ func (c *cursor) Last(ctx context.Context) (*chain.Beacon, error) { // seekPosition updates the cursor position in the database for the next operation to work func (c *cursor) seekPosition(ctx context.Context, round uint64) error { + ctx, span := metrics.NewSpan(ctx, "pgStore.Cursor.seekPosition") + defer span.End() + select { case <-ctx.Done(): return ctx.Err() diff --git a/chain/postgresdb/pgdb/pgdb_test.go b/chain/postgresdb/pgdb/pgdb_test.go index 560f3cd53..5595a61b3 100644 --- a/chain/postgresdb/pgdb/pgdb_test.go +++ b/chain/postgresdb/pgdb/pgdb_test.go @@ -55,7 +55,7 @@ func Test_OrderStorePG(t *testing.T) { store, err := pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() b0 := &chain.Beacon{ @@ -107,7 +107,7 @@ func TestStore_Cursor(t *testing.T) { dbStore, err := pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() sigs := map[int][]byte{ @@ -181,7 +181,7 @@ func Test_StorePG(t *testing.T) { store, err := pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() doStorePgTest(ctx, t, store, l, db, beaconName, prevMatters) @@ -198,7 +198,7 @@ func Test_WithReservedIdentifier(t *testing.T) { store, err := pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, store.Close(ctx)) + require.NoError(t, store.Close()) }() doStorePgTest(ctx, t, store, l, db, beaconName, prevMatters) @@ -263,7 +263,7 @@ func doStorePgTest(ctx context.Context, t *testing.T, dbStore *pgdb.Store, l log dbStore, err = pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() require.NoError(t, dbStore.Put(ctx, b1)) @@ -278,7 +278,7 @@ func doStorePgTest(ctx context.Context, t *testing.T, dbStore *pgdb.Store, l log dbStore, err = pgdb.NewStore(ctx, l, db, beaconName) require.NoError(t, err) defer func() { - require.NoError(t, dbStore.Close(ctx)) + require.NoError(t, dbStore.Close()) }() err = dbStore.Put(ctx, b1) diff --git a/chain/postgresdb/schema/schema.go b/chain/postgresdb/schema/schema.go index 8275812e1..020b1ce64 100644 --- a/chain/postgresdb/schema/schema.go +++ b/chain/postgresdb/schema/schema.go @@ -10,6 +10,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/drand/drand/chain/postgresdb/database" + "github.com/drand/drand/metrics" ) var ( @@ -20,6 +21,9 @@ var ( // Migrate attempts to bring the schema for db up to date with the migrations // defined in this package. func Migrate(ctx context.Context, db *sqlx.DB) error { + ctx, span := metrics.NewSpan(ctx, "database.Migrate") + defer span.End() + if err := database.StatusCheck(ctx, db); err != nil { return fmt.Errorf("status check database: %w", err) } diff --git a/chain/store.go b/chain/store.go index a8a5c5a10..1ed4d0d0c 100644 --- a/chain/store.go +++ b/chain/store.go @@ -19,7 +19,7 @@ type Store interface { Last(context.Context) (*Beacon, error) Get(ctx context.Context, round uint64) (*Beacon, error) Cursor(context.Context, func(context.Context, Cursor) error) error - Close(context.Context) error + Close() error Del(ctx context.Context, round uint64) error SaveTo(ctx context.Context, w io.Writer) error } diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index e398080e5..668c7b3f1 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -22,6 +22,7 @@ import ( // NewMockHTTPPublicServer creates a mock drand HTTP server for testing. func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chain.Info, context.CancelFunc, func(bool)) { t.Helper() + ctx := context.Background() server := mock.NewMockServer(t, badSecondRound, sch, clk) client := core.Proxy(server) @@ -64,7 +65,7 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche go httpServer.Serve(listener) return listener.Addr().String(), chainInfo, func() { - httpServer.Shutdown(context.Background()) + httpServer.Shutdown(ctx) cancel() }, server.(mock.MockService).EmitRand } diff --git a/cmd/drand-cli/cli.go b/cmd/drand-cli/cli.go index 3a69e3d06..5724b3f69 100644 --- a/cmd/drand-cli/cli.go +++ b/cmd/drand-cli/cli.go @@ -101,6 +101,21 @@ var metricsFlag = &cli.StringFlag{ EnvVars: []string{"DRAND_METRICS"}, } +var tracesFlag = &cli.StringFlag{ + Name: "traces", + Usage: "Publish metrics to the specific OpenTelemetry compatible host:port server. E.g. 127.0.0.1:4317", + EnvVars: []string{"DRAND_TRACES"}, +} + +var tracesProbabilityFlag = &cli.Float64Flag{ + Name: "traces-probability", + Usage: "The probability for a certain trace to end up being collected." + + "Between 0.0 and 1.0 values, that corresponds to 0% and 100%." + + "Be careful as a high probability ratio can produce a lot of data.", + EnvVars: []string{"DRAND_TRACES_PROBABILITY"}, + Value: 0.05, +} + var privListenFlag = &cli.StringFlag{ Name: "private-listen", Usage: "Set the listening (binding) address of the private API. Useful if you have some kind of proxy.", @@ -376,7 +391,8 @@ var appCommands = []*cli.Command{ Name: "start", Usage: "Start the drand daemon.", Flags: toArray(folderFlag, tlsCertFlag, tlsKeyFlag, - insecureFlag, controlFlag, privListenFlag, pubListenFlag, metricsFlag, + insecureFlag, controlFlag, privListenFlag, pubListenFlag, + metricsFlag, tracesFlag, tracesProbabilityFlag, certsDirFlag, pushFlag, verboseFlag, oldGroupFlag, skipValidationFlag, jsonFlag, beaconIDFlag, storageTypeFlag, pgDSNFlag, memDBSizeFlag), @@ -824,7 +840,7 @@ func checkMigration(c *cli.Context, l log.Logger) error { func testWindows(c *cli.Context) error { // x509 not available on windows: must run without TLS - if runtime.GOOS == "windows" && !c.Bool("tls-disable") { + if runtime.GOOS == "windows" && !c.Bool(insecureFlag.Name) { return errors.New("TLS is not available on Windows, please disable TLS") } return nil @@ -1020,6 +1036,7 @@ func checkIdentityAddress(lg log.Logger, conf *core.Config, addr string, tls boo // the head of the chain func deleteBeaconCmd(c *cli.Context, l log.Logger) error { conf := contextToConfig(c, l) + ctx := c.Context startRoundStr := c.Args().First() sr, err := strconv.Atoi(startRoundStr) @@ -1036,7 +1053,6 @@ func deleteBeaconCmd(c *cli.Context, l log.Logger) error { verbose := isVerbose(c) - ctx := c.Context sch, err := crypto.GetSchemeFromEnv() if err != nil { return err @@ -1056,7 +1072,7 @@ func deleteBeaconCmd(c *cli.Context, l log.Logger) error { if err != nil { return fmt.Errorf("beacon id [%s] - invalid bolt store creation: %w", beaconID, err) } - defer store.Close(ctx) + defer store.Close() lastBeacon, err := store.Last(ctx) if err != nil { @@ -1118,7 +1134,7 @@ func getGroup(c *cli.Context) (*key.Group, error) { } func checkArgs(c *cli.Context) error { - if c.Bool("tls-disable") { + if c.Bool(insecureFlag.Name) { if c.IsSet("tls-cert") || c.IsSet("tls-key") { return fmt.Errorf("option 'tls-disable' used with 'tls-cert' or 'tls-key': combination is not valid") } @@ -1153,7 +1169,7 @@ func contextToConfig(c *cli.Context, l log.Logger) *core.Config { } opts = append(opts, core.WithVersion(fmt.Sprintf("drand/%s (%s)", version, gitCommit))) - if c.Bool("tls-disable") { + if c.Bool(insecureFlag.Name) { opts = append(opts, core.WithInsecure()) } else { certPath, keyPath := c.String("tls-cert"), c.String("tls-key") @@ -1168,6 +1184,17 @@ func contextToConfig(c *cli.Context, l log.Logger) *core.Config { opts = append(opts, core.WithTrustedCerts(paths...)) } + if c.IsSet(tracesFlag.Name) { + opts = append(opts, core.WithTracesEndpoint(c.String(tracesFlag.Name))) + } + + if c.IsSet(tracesProbabilityFlag.Name) { + opts = append(opts, core.WithTracesProbability(c.Float64(tracesProbabilityFlag.Name))) + } else { + //nolint:gomnd // Reset the trace probability to 5% + opts = append(opts, core.WithTracesProbability(0.05)) + } + switch chain.StorageType(c.String(storageTypeFlag.Name)) { case chain.BoltDB: opts = append(opts, core.WithDBStorageEngine(chain.BoltDB)) diff --git a/cmd/drand-cli/cli_test.go b/cmd/drand-cli/cli_test.go index d51b1bac5..f1d21c903 100644 --- a/cmd/drand-cli/cli_test.go +++ b/cmd/drand-cli/cli_test.go @@ -130,7 +130,7 @@ func TestDeleteBeacon(t *testing.T) { require.NoError(t, err) require.NotNil(t, b) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} diff --git a/cmd/drand-cli/daemon.go b/cmd/drand-cli/daemon.go index 5a1af7c09..69b6cdb4c 100644 --- a/cmd/drand-cli/daemon.go +++ b/cmd/drand-cli/daemon.go @@ -4,31 +4,49 @@ import ( "fmt" "github.com/urfave/cli/v2" + "go.opentelemetry.io/otel/attribute" "github.com/drand/drand/core" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" ) func startCmd(c *cli.Context, l log.Logger) error { conf := contextToConfig(c, l) + ctx := c.Context + + tracer, tracerShutdown := metrics.InitTracer("drand", conf.TracesEndpoint(), conf.TracesProbability()) + defer tracerShutdown(ctx) + + ctx, span := tracer.Start(ctx, "startCmd") // Create and start drand daemon - drandDaemon, err := core.NewDrandDaemon(conf) + drandDaemon, err := core.NewDrandDaemon(ctx, conf) if err != nil { - return fmt.Errorf("can't instantiate drand daemon %w", err) + err = fmt.Errorf("can't instantiate drand daemon %w", err) + span.RecordError(err) + span.End() + return err } singleBeacon := false if c.IsSet(beaconIDFlag.Name) { singleBeacon = true } + span.SetAttributes( + attribute.Bool("singleBeaconMode", singleBeacon), + ) // Check stores and start BeaconProcess - err = drandDaemon.LoadBeaconsFromDisk(c.String(metricsFlag.Name), singleBeacon, c.String(beaconIDFlag.Name)) + err = drandDaemon.LoadBeaconsFromDisk(ctx, c.String(metricsFlag.Name), singleBeacon, c.String(beaconIDFlag.Name)) if err != nil { - return fmt.Errorf("couldn't load existing beacons: %w", err) + err = fmt.Errorf("couldn't load existing beacons: %w", err) + span.RecordError(err) + span.End() + return err } + span.End() <-drandDaemon.WaitExit() return nil } diff --git a/cmd/drand-cli/public.go b/cmd/drand-cli/public.go index a2bf81334..c80bf5c72 100644 --- a/cmd/drand-cli/public.go +++ b/cmd/drand-cli/public.go @@ -70,6 +70,7 @@ func getPublicRandomness(c *cli.Context, lg log.Logger) error { } func getChainInfo(c *cli.Context, lg log.Logger) error { + ctx := c.Context var err error chainHash := make([]byte, 0) if c.IsSet(hashInfoNoReq.Name) { @@ -93,7 +94,7 @@ func getChainInfo(c *cli.Context, lg log.Logger) error { if err != nil { return fmt.Errorf("invalid address given: %w", err) } - ci, err = grpcClient.ChainInfo(net.CreatePeer(addr, !c.Bool("tls-disable"))) + ci, err = grpcClient.ChainInfo(ctx, net.CreatePeer(addr, !c.Bool("tls-disable"))) if err == nil { break } diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 7e450df38..80e96cf14 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/hex" "fmt" "net" @@ -47,10 +48,31 @@ var metricsFlag = &cli.StringFlag{ EnvVars: []string{"DRAND_RELAY_METRICS"}, } +var tracesFlag = &cli.StringFlag{ + Name: "traces", + Usage: "Publish metrics to the specific OpenTelemetry compatible host:port server. E.g. 127.0.0.1:4317", + EnvVars: []string{"DRAND_TRACES"}, +} + +var tracesProbabilityFlag = &cli.Float64Flag{ + Name: "traces-probability", + Usage: "Publish metrics to the specific OpenTelemetry compatible host:port server.", + EnvVars: []string{"DRAND_TRACES_PROBABILITY"}, + Value: 0.05, +} + // Relay a GRPC connection to an HTTP server. // //nolint:gocyclo,funlen func Relay(c *cli.Context) error { + tracesProbability := 0.1 + if c.IsSet(tracesProbabilityFlag.Name) { + tracesProbability = c.Float64(tracesProbabilityFlag.Name) + } + + _, tracerShutdown := metrics.InitTracer("drand_relay", c.String(tracesFlag.Name), tracesProbability) + defer tracerShutdown(c.Context) + cliLog := log.FromContextOrDefault(c.Context) version := common.GetAppVersion() @@ -169,7 +191,7 @@ func main() { Name: "relay", Version: version.String(), Usage: "Relay a Drand group to a public HTTP Rest API", - Flags: append(lib.ClientFlags, lib.HashListFlag, listenFlag, accessLogFlag, metricsFlag), + Flags: append(lib.ClientFlags, lib.HashListFlag, listenFlag, accessLogFlag, metricsFlag, tracesFlag, tracesProbabilityFlag), Action: func(ctx *cli.Context) error { ctx.Context = log.ToContext(ctx.Context, lg) return Relay(ctx) diff --git a/core/client_public.go b/core/client_public.go index 8f8691b45..375bec518 100644 --- a/core/client_public.go +++ b/core/client_public.go @@ -7,6 +7,7 @@ import ( "github.com/drand/drand/chain" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/common" "github.com/drand/drand/protobuf/drand" @@ -54,9 +55,12 @@ func NewGrpcClientFromCertWithLogger(lg log.Logger, chainHash []byte, c *net.Cer } // ChainInfo returns the chain info as reported by the given peer. -func (c *Client) ChainInfo(p net.Peer) (*chain.Info, error) { +func (c *Client) ChainInfo(ctx context.Context, p net.Peer) (*chain.Info, error) { + ctx, span := metrics.NewSpan(ctx, "c.ChainInfo") + defer span.End() + metadata := common.Metadata{ChainHash: c.chainHash} - resp, err := c.client.ChainInfo(context.TODO(), p, &drand.ChainInfoRequest{Metadata: &metadata}) + resp, err := c.client.ChainInfo(ctx, p, &drand.ChainInfoRequest{Metadata: &metadata}) if err != nil { return nil, err } diff --git a/core/config.go b/core/config.go index ae141754a..d9fb2613d 100644 --- a/core/config.go +++ b/core/config.go @@ -40,12 +40,14 @@ type Config struct { pgDSN string pgConn *sqlx.DB memDBSize int - dkgCallback func(*key.Share, *key.Group) + dkgCallback func(context.Context, *key.Share, *key.Group) certPath string keyPath string certmanager *net.CertManager logger log.Logger clock clock.Clock + tracesEndpoint string + tracesProbability float64 } // NewConfig returns the config to pass to drand with the default options set @@ -314,3 +316,27 @@ func WithVersion(version string) ConfigOption { d.version = version } } + +// WithTracesEndpoint sets the receiver for the tracing data +func WithTracesEndpoint(tracesEndpoint string) ConfigOption { + return func(d *Config) { + d.tracesEndpoint = tracesEndpoint + } +} + +// TracesEndpoint retrieves the configured tracing data endpoint +func (d *Config) TracesEndpoint() string { + return d.tracesEndpoint +} + +// WithTracesProbability sets the probability of for traces to be collected and sent to the server +func WithTracesProbability(tracesProbability float64) ConfigOption { + return func(d *Config) { + d.tracesProbability = tracesProbability + } +} + +// TracesProbability retrieves the probability of for traces to be collected and sent to the server +func (d *Config) TracesProbability() float64 { + return d.tracesProbability +} diff --git a/core/drand_beacon.go b/core/drand_beacon.go index ac3707235..f30687c3d 100644 --- a/core/drand_beacon.go +++ b/core/drand_beacon.go @@ -68,6 +68,7 @@ type BeaconProcess struct { } func NewBeaconProcess( + ctx context.Context, log dlog.Logger, store key.Store, completedDKGs chan dkg.SharingOutput, @@ -76,12 +77,18 @@ func NewBeaconProcess( privGateway *net.PrivateGateway, pubGateway *net.PublicGateway, ) (*BeaconProcess, error) { + _, span := metrics.NewSpan(ctx, "dd.NewBeaconProcess") + defer span.End() + priv, err := store.LoadKeyPair(nil) if err != nil { + span.RecordError(err) return nil, err } if err := priv.Public.ValidSignature(); err != nil { - return nil, fmt.Errorf("INVALID SELF SIGNATURE %w. Action: run `drand util self-sign`", err) + err := fmt.Errorf("INVALID SELF SIGNATURE %w. Action: run `drand util self-sign`", err) + span.RecordError(err) + return nil, err } bp := &BeaconProcess{ @@ -104,7 +111,10 @@ var ErrDKGNotStarted = errors.New("DKG not started") // Load restores a drand instance that is ready to serve randomness, with a // pre-existing distributed share. // Returns 'true' if this BeaconProcess is a fresh run, returns 'false' otherwise -func (bp *BeaconProcess) Load() error { +func (bp *BeaconProcess) Load(ctx context.Context) error { + ctx, span := metrics.NewSpan(ctx, "bp.Load") + defer span.End() + var err error beaconID := bp.getBeaconID() @@ -152,10 +162,14 @@ func (bp *BeaconProcess) Load() error { // StartBeacon initializes the beacon if needed and launch a go // routine that runs the generation loop. -func (bp *BeaconProcess) StartBeacon(catchup bool) error { - ctx := context.Background() +func (bp *BeaconProcess) StartBeacon(ctx context.Context, catchup bool) error { + ctx, span := metrics.NewSpan(ctx, "bp.StartBeacon") + defer span.End() + b, err := bp.newBeacon(ctx) if err != nil { + span.RecordError(err) + span.End() bp.log.Errorw("", "init_beacon", err) return err } @@ -165,8 +179,9 @@ func (bp *BeaconProcess) StartBeacon(catchup bool) error { // This doesn't need to be called async. // In the future, we might want to wait and return any errors from it too. // TODO: Add error handling for this method and handle it here. - b.Catchup() - } else if err := b.Start(); err != nil { + b.Catchup(ctx) + } else if err := b.Start(ctx); err != nil { + span.RecordError(err) bp.log.Errorw("", "beacon_start", err) return err } @@ -325,6 +340,9 @@ func (bp *BeaconProcess) joinNetwork(dkgOutput *dkg.SharingOutput) error { // Stop simply stops all drand operations. func (bp *BeaconProcess) Stop(ctx context.Context) { + ctx, span := metrics.NewSpan(ctx, "bp.Stop") + defer span.End() + bp.state.RLock() select { case <-bp.exitCh: @@ -344,7 +362,7 @@ func (bp *BeaconProcess) Stop(ctx context.Context) { } bp.state.RUnlock() - bp.StopBeacon() + bp.StopBeacon(ctx) } // WaitExit returns a channel that signals when drand stops its operations @@ -353,6 +371,9 @@ func (bp *BeaconProcess) WaitExit() chan bool { } func (bp *BeaconProcess) createDBStore(ctx context.Context) (chain.Store, error) { + ctx, span := metrics.NewSpan(ctx, "bp.createDBStore") + defer span.End() + beaconName := commonutils.GetCanonicalBeaconID(bp.beaconID) var dbStore chain.Store var err error @@ -388,6 +409,9 @@ func (bp *BeaconProcess) createDBStore(ctx context.Context) (chain.Store, error) } func (bp *BeaconProcess) newBeacon(ctx context.Context) (*beacon.Handler, error) { + ctx, span := metrics.NewSpan(ctx, "bp.newBeacon") + defer span.End() + bp.state.Lock() defer bp.state.Unlock() @@ -411,7 +435,6 @@ func (bp *BeaconProcess) newBeacon(ctx context.Context) (*beacon.Handler, error) } if bp.opts.dbStorageEngine == chain.MemDB { - ctx := context.Background() err := bp.storeCurrentFromPeerNetwork(ctx, store) if err != nil { if errors.Is(err, errNoRoundInPeers) { @@ -425,7 +448,7 @@ func (bp *BeaconProcess) newBeacon(ctx context.Context) (*beacon.Handler, error) } } - b, err := beacon.NewHandler(bp.privGateway.ProtocolClient, store, conf, bp.log, bp.version) + b, err := beacon.NewHandler(ctx, bp.privGateway.ProtocolClient, store, conf, bp.log, bp.version) if err != nil { return nil, err } @@ -452,14 +475,17 @@ func checkGroup(l dlog.Logger, group *key.Group) { } // StopBeacon stops the beacon generation process and resets it. -func (bp *BeaconProcess) StopBeacon() { +func (bp *BeaconProcess) StopBeacon(ctx context.Context) { + ctx, span := metrics.NewSpan(ctx, "bp.StopBeacon") + defer span.End() + bp.state.Lock() defer bp.state.Unlock() if bp.beacon == nil { return } - bp.beacon.Stop() + bp.beacon.Stop(ctx) bp.beacon = nil } @@ -487,6 +513,9 @@ func (bp *BeaconProcess) newMetadata() *common.Metadata { var errNoRoundInPeers = errors.New("could not find round") func (bp *BeaconProcess) storeCurrentFromPeerNetwork(ctx context.Context, store chain.Store) error { + ctx, span := metrics.NewSpan(ctx, "bp.storeCurrentFromPeerNetwork") + defer span.End() + clkNow := bp.opts.clock.Now().Unix() if bp.group == nil { return nil @@ -534,6 +563,9 @@ func (bp *BeaconProcess) storeCurrentFromPeerNetwork(ctx context.Context, store } func (bp *BeaconProcess) loadBeaconFromPeers(ctx context.Context, targetRound uint64, peers []net.Peer) (chain.Beacon, error) { + ctx, span := metrics.NewSpan(ctx, "bp.loadBeaconFromPeers") + defer span.End() + select { case <-ctx.Done(): return chain.Beacon{}, ctx.Err() diff --git a/core/drand_beacon_control.go b/core/drand_beacon_control.go index 2d1409ae7..659e20782 100644 --- a/core/drand_beacon_control.go +++ b/core/drand_beacon_control.go @@ -10,6 +10,7 @@ import ( "github.com/drand/drand/key" clock "github.com/jonboulle/clockwork" + "go.opentelemetry.io/otel/attribute" "github.com/drand/drand/chain" "github.com/drand/drand/chain/beacon" @@ -24,7 +25,10 @@ import ( // PublicKey is a functionality of Control Service defined in protobuf/control // that requests the long term public key of the drand node running locally -func (bp *BeaconProcess) PublicKey(context.Context, *drand.PublicKeyRequest) (*drand.PublicKeyResponse, error) { +func (bp *BeaconProcess) PublicKey(ctx context.Context, _ *drand.PublicKeyRequest) (*drand.PublicKeyResponse, error) { + _, span := metrics.NewSpan(ctx, "bp.PublicKey") + defer span.End() + bp.state.RLock() defer bp.state.RUnlock() @@ -48,7 +52,10 @@ func (bp *BeaconProcess) PublicKey(context.Context, *drand.PublicKeyRequest) (*d } // GroupFile replies with the distributed key in the response -func (bp *BeaconProcess) GroupFile(context.Context, *drand.GroupRequest) (*drand.GroupPacket, error) { +func (bp *BeaconProcess) GroupFile(ctx context.Context, _ *drand.GroupRequest) (*drand.GroupPacket, error) { + _, span := metrics.NewSpan(ctx, "bp.GroupFile") + defer span.End() + bp.state.RLock() defer bp.state.RUnlock() @@ -63,6 +70,9 @@ func (bp *BeaconProcess) GroupFile(context.Context, *drand.GroupRequest) (*drand // BackupDatabase triggers a backup of the primary database. func (bp *BeaconProcess) BackupDatabase(ctx context.Context, req *drand.BackupDBRequest) (*drand.BackupDBResponse, error) { + ctx, span := metrics.NewSpan(ctx, "bp.BackupDatabase") + defer span.End() + bp.state.RLock() if bp.beacon == nil { bp.state.RUnlock() @@ -82,11 +92,17 @@ func (bp *BeaconProcess) BackupDatabase(ctx context.Context, req *drand.BackupDB // PingPong simply responds with an empty packet, proving that this drand node // is up and alive. -func (bp *BeaconProcess) PingPong(context.Context, *drand.Ping) (*drand.Pong, error) { +func (bp *BeaconProcess) PingPong(ctx context.Context, _ *drand.Ping) (*drand.Pong, error) { + _, span := metrics.NewSpan(ctx, "bp.Ping") + defer span.End() + return &drand.Pong{Metadata: bp.newMetadata()}, nil } func (bp *BeaconProcess) RemoteStatus(ctx context.Context, in *drand.RemoteStatusRequest) (*drand.RemoteStatusResponse, error) { + ctx, span := metrics.NewSpan(ctx, "bp.RemoteStatus") + defer span.End() + replies := make(map[string]*drand.StatusResponse) nodes := in.GetAddresses() if len(nodes) == 0 { @@ -139,6 +155,9 @@ func (bp *BeaconProcess) RemoteStatus(ctx context.Context, in *drand.RemoteStatu // func (bp *BeaconProcess) Status(ctx context.Context, in *drand.StatusRequest) (*drand.StatusResponse, error) { + ctx, span := metrics.NewSpan(ctx, "bp.Status") + defer span.End() + bp.state.RLock() defer bp.state.RUnlock() @@ -207,6 +226,10 @@ func (bp *BeaconProcess) Status(ctx context.Context, in *drand.StatusRequest) (* p := net.CreatePeer(remoteAddress, addr.GetTls()) // we use an anonymous function to not leak the defer in the for loop func() { + ctx, span := metrics.NewSpan(ctx, "bp.Status.sendingHome") + span.SetAttributes(attribute.String("nodeAddr", remoteAddress)) + defer span.End() + // Simply try to ping him see if he replies tc, cancel := context.WithTimeout(ctx, callMaxTimeout) defer cancel() @@ -233,18 +256,27 @@ func (bp *BeaconProcess) Status(ctx context.Context, in *drand.StatusRequest) (* return packet, nil } -func (bp *BeaconProcess) ListSchemes(context.Context, *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { +func (bp *BeaconProcess) ListSchemes(ctx context.Context, _ *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { + _, span := metrics.NewSpan(ctx, "bp.ListSchemes") + defer span.End() + return &drand.ListSchemesResponse{Ids: crypto.ListSchemes(), Metadata: bp.newMetadata()}, nil } -func (bp *BeaconProcess) ListBeaconIDs(context.Context, *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { +func (bp *BeaconProcess) ListBeaconIDs(ctx context.Context, _ *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { + _, span := metrics.NewSpan(ctx, "bp.ListBeaconIDs") + defer span.End() + return nil, fmt.Errorf("method not implemented") } // StartFollowChain syncs up with a chain from other nodes // -//nolint:funlen,gocyclo -func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream drand.Control_StartFollowChainServer) error { +//nolint:funlen,gocyclo,lll +func (bp *BeaconProcess) StartFollowChain(ctx context.Context, req *drand.StartSyncRequest, stream drand.Control_StartFollowChainServer) error { + ctx, span := metrics.NewSpan(ctx, "bp.StartFollowChain") + defer span.End() + // TODO replace via a more independent chain manager that manages the // transition from following -> participating bp.state.Lock() @@ -260,7 +292,7 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr // context will signal and it will stop. If we want the following to // continue nevertheless we can use the next line by using a new context. // ctx, cancel := context.WithCancel(context.Background()) - ctx, cancel := context.WithCancel(stream.Context()) + ctx, cancel := context.WithCancel(ctx) bp.syncerCancel = cancel bp.state.Unlock() @@ -287,7 +319,7 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr beaconID := bp.getBeaconID() - info, err := chainInfoFromPeers(stream.Context(), bp.privGateway, peers, bp.log, bp.version, beaconID) + info, err := bp.chainInfoFromPeers(ctx, bp.privGateway, peers, bp.log, bp.version, beaconID) if err != nil { return err } @@ -313,7 +345,7 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr // TODO find a better place to put that if err := store.Put(ctx, chain.GenesisBeacon(info.GenesisSeed)); err != nil { bp.log.Errorw("", "start_follow_chain", "unable to insert genesis block", "err", err) - store.Close(ctx) + store.Close() return fmt.Errorf("unable to insert genesis block: %w", err) } @@ -322,22 +354,22 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr if err != nil { return err } - ss, err := beacon.NewSchemeStore(store, sch) + ss, err := beacon.NewSchemeStore(ctx, store, sch) if err != nil { return err } // register callback to notify client of progress cbStore := beacon.NewCallbackStore(bp.log, ss) - defer cbStore.Close(ctx) + defer cbStore.Close() - cb, done := sendProgressCallback(stream, req.GetUpTo(), info, bp.opts.clock, bp.log) + cb, done := bp.sendProgressCallback(ctx, stream, req.GetUpTo(), info, bp.opts.clock, bp.log) addr := net.RemoteAddress(stream.Context()) cbStore.AddCallback(addr, cb) defer cbStore.RemoveCallback(addr) - syncer, err := beacon.NewSyncManager(&beacon.SyncConfig{ + syncer, err := beacon.NewSyncManager(ctx, &beacon.SyncConfig{ Log: bp.log, Store: cbStore, BoltdbStore: store, @@ -359,7 +391,7 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr for { syncCtx, syncCancel := context.WithCancel(ctx) go func() { - errChan <- syncer.Sync(syncCtx, beacon.NewRequestInfo(req.GetUpTo(), peers)) + errChan <- syncer.Sync(syncCtx, beacon.NewRequestInfo(span.SpanContext(), req.GetUpTo(), peers)) }() // wait for all the callbacks to be called and progress sent before returning select { case <-done: @@ -380,6 +412,10 @@ func (bp *BeaconProcess) StartFollowChain(req *drand.StartSyncRequest, stream dr // StartCheckChain checks a chain for validity and pulls invalid beacons from other nodes func (bp *BeaconProcess) StartCheckChain(req *drand.StartSyncRequest, stream drand.Control_StartCheckChainServer) error { + ctx := stream.Context() + ctx, span := metrics.NewSpan(ctx, "bp.StartCheckChain") + defer span.End() + logger := bp.log.Named("CheckChain") if bp.beacon == nil { @@ -396,7 +432,7 @@ func (bp *BeaconProcess) StartCheckChain(req *drand.StartSyncRequest, stream dra // context given to the syncer // NOTE: this means that if the client quits the requests, the syncing // context will signal it, and it will stop. - ctx, cancel := context.WithCancel(stream.Context()) + ctx, cancel := context.WithCancel(ctx) bp.syncerCancel = cancel bp.state.Unlock() defer func() { @@ -409,7 +445,7 @@ func (bp *BeaconProcess) StartCheckChain(req *drand.StartSyncRequest, stream dra }() // we don't monitor the channel for this one, instead we'll error out if needed - cb, _ := sendPlainProgressCallback(stream, logger, false) + cb, _ := bp.sendPlainProgressCallback(ctx, stream, logger, false) peers := make([]net.Peer, 0, len(req.GetNodes())) for _, addr := range req.GetNodes() { @@ -448,7 +484,7 @@ func (bp *BeaconProcess) StartCheckChain(req *drand.StartSyncRequest, stream dra time.Sleep(time.Second) // we need the channel to make sure the client has received the progress - cb, done := sendPlainProgressCallback(stream, logger, false) + cb, done := bp.sendPlainProgressCallback(ctx, stream, logger, false) logger.Infow("Faulty beacons detected in chain, correcting now", "dry-run", false) logger.Debugw("Faulty beacons", "List", faultyBeacons) @@ -470,9 +506,12 @@ func (bp *BeaconProcess) StartCheckChain(req *drand.StartSyncRequest, stream dra } // chainInfoFromPeers attempts to fetch chain info from one of the passed peers. -func chainInfoFromPeers(ctx context.Context, privGateway *net.PrivateGateway, +func (bp *BeaconProcess) chainInfoFromPeers(ctx context.Context, privGateway *net.PrivateGateway, peers []net.Peer, l log.Logger, version commonutils.Version, beaconID string, ) (*chain.Info, error) { + ctx, span := metrics.NewSpan(ctx, "bp.chainInfoFromPeers") + defer span.End() + // we first craft our request request := new(drand.ChainInfoRequest) request.Metadata = &common.Metadata{BeaconID: beaconID, NodeVersion: version.ToProto()} @@ -501,13 +540,17 @@ func chainInfoFromPeers(ctx context.Context, privGateway *net.PrivateGateway, // sendProgressCallback returns a function that sends SyncProgress on the // passed stream. It also returns a channel that closes when the callback is // called with a beacon whose round matches the passed upTo value. -func sendProgressCallback( +func (bp *BeaconProcess) sendProgressCallback( + ctx context.Context, stream drand.Control_StartFollowChainServer, // not ideal since we also reuse it for the StartCheckChain upTo uint64, info *chain.Info, clk clock.Clock, l log.Logger, ) (cb beacon.CallbackFunc, done chan struct{}) { + ctx, span := metrics.NewSpan(ctx, "bp.StartCheckChain") + defer span.End() + logger := l.Named("progressCb") targ := chain.CurrentRound(clk.Now().Unix(), info.Period, info.GenesisTime) if upTo != 0 && upTo < targ { @@ -515,7 +558,7 @@ func sendProgressCallback( } var plainProgressCb func(a, b uint64) - plainProgressCb, done = sendPlainProgressCallback(stream, logger, upTo == 0) + plainProgressCb, done = bp.sendPlainProgressCallback(ctx, stream, logger, upTo == 0) cb = func(b *chain.Beacon, closed bool) { if closed { return @@ -530,11 +573,15 @@ func sendProgressCallback( // sendPlainProgressCallback returns a function that sends SyncProgress on the // passed stream. It also returns a channel that closes when the callback is // called with a value whose round matches the passed upTo value. -func sendPlainProgressCallback( +func (bp *BeaconProcess) sendPlainProgressCallback( + ctx context.Context, stream drand.Control_StartFollowChainServer, l log.Logger, keepFollowing bool, ) (cb func(curr, targ uint64), done chan struct{}) { + _, span := metrics.NewSpan(ctx, "bp.sendPlainProgressCallback") + defer span.End() + done = make(chan struct{}) cb = func(curr, targ uint64) { @@ -559,6 +606,7 @@ func sendPlainProgressCallback( close(done) } } + //nolint:nakedret return } diff --git a/core/drand_beacon_metrics.go b/core/drand_beacon_metrics.go index 88fdd3a10..1bc3f3ac5 100644 --- a/core/drand_beacon_metrics.go +++ b/core/drand_beacon_metrics.go @@ -1,16 +1,21 @@ package core import ( + "context" "errors" "fmt" "net/http" "github.com/drand/drand/common" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" ) // MetricsHandlerForPeer returns a handler for retrieving metric information from a peer in this group -func (bp *BeaconProcess) MetricsHandlerForPeer(addr string) (http.Handler, error) { +func (bp *BeaconProcess) MetricsHandlerForPeer(ctx context.Context, addr string) (http.Handler, error) { + ctx, span := metrics.NewSpan(ctx, "bp.MetricsHandlerForPeer") + defer span.End() + if bp.group == nil { return nil, fmt.Errorf("%w for Beacon ID: %s", common.ErrNotPartOfGroup, bp.getBeaconID()) } @@ -27,7 +32,7 @@ func (bp *BeaconProcess) MetricsHandlerForPeer(addr string) (http.Handler, error for _, n := range bp.group.Nodes { if n.Address() == addr { p := net.CreatePeer(n.Address(), n.IsTLS()) - h, e := hc.HandleHTTP(p) + h, e := hc.HandleHTTP(ctx, p) if e == nil { return h, nil } diff --git a/core/drand_beacon_public.go b/core/drand_beacon_public.go index f21c6fcbc..354696d01 100644 --- a/core/drand_beacon_public.go +++ b/core/drand_beacon_public.go @@ -8,28 +8,38 @@ import ( "github.com/drand/drand/chain" "github.com/drand/drand/chain/beacon" "github.com/drand/drand/crypto" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/drand" ) // PartialBeacon receives a beacon generation request and answers // with the partial signature from this drand node. -func (bp *BeaconProcess) PartialBeacon(c context.Context, in *drand.PartialBeaconPacket) (*drand.Empty, error) { +func (bp *BeaconProcess) PartialBeacon(ctx context.Context, in *drand.PartialBeaconPacket) (*drand.Empty, error) { + ctx, span := metrics.NewSpan(ctx, "bp.PartialBeacon") + defer span.End() + bp.state.RLock() // we need to defer unlock here to avoid races during the partial processing defer bp.state.RUnlock() inst := bp.beacon if inst == nil || len(bp.chainHash) == 0 { - return nil, errors.New("DKG not finished yet") + err := errors.New("DKG not finished yet") + span.RecordError(err) + return nil, err } - _, err := inst.ProcessPartialBeacon(c, in) + _, err := inst.ProcessPartialBeacon(ctx, in) + span.RecordError(err) return &drand.Empty{Metadata: bp.newMetadata()}, err } // PublicRand returns a public random beacon according to the request. If the Round // field is 0, then it returns the last one generated. func (bp *BeaconProcess) PublicRand(ctx context.Context, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { + ctx, span := metrics.NewSpan(ctx, "bp.PublicRand") + defer span.End() + var addr = net.RemoteAddress(ctx) bp.state.RLock() @@ -103,8 +113,11 @@ func (bp *BeaconProcess) PublicRandStream(req *drand.PublicRandRequest, stream d } // Home provides the address the local node is listening -func (bp *BeaconProcess) Home(c context.Context, _ *drand.HomeRequest) (*drand.HomeResponse, error) { - bp.log.With("module", "public").Infow("", "home", net.RemoteAddress(c)) +func (bp *BeaconProcess) Home(ctx context.Context, _ *drand.HomeRequest) (*drand.HomeResponse, error) { + ctx, span := metrics.NewSpan(ctx, "bp.Home") + defer span.End() + + bp.log.With("module", "public").Infow("", "home", net.RemoteAddress(ctx)) return &drand.HomeResponse{ Status: fmt.Sprintf("drand up and running on %s", @@ -114,7 +127,10 @@ func (bp *BeaconProcess) Home(c context.Context, _ *drand.HomeRequest) (*drand.H } // ChainInfo replies with the chain information this node participates to -func (bp *BeaconProcess) ChainInfo(context.Context, *drand.ChainInfoRequest) (*drand.ChainInfoPacket, error) { +func (bp *BeaconProcess) ChainInfo(ctx context.Context, _ *drand.ChainInfoRequest) (*drand.ChainInfoPacket, error) { + _, span := metrics.NewSpan(ctx, "bp.ChainInfo") + defer span.End() + bp.state.RLock() group := bp.group chainHash := bp.chainHash @@ -148,7 +164,10 @@ func (bp *BeaconProcess) SyncChain(req *drand.SyncRequest, stream drand.Protocol } // GetIdentity returns the identity of this drand node -func (bp *BeaconProcess) GetIdentity(context.Context, *drand.IdentityRequest) (*drand.IdentityResponse, error) { +func (bp *BeaconProcess) GetIdentity(ctx context.Context, _ *drand.IdentityRequest) (*drand.IdentityResponse, error) { + _, span := metrics.NewSpan(ctx, "bp.GetIdentity") + defer span.End() + i := bp.priv.Public.ToProto() response := &drand.IdentityResponse{ diff --git a/core/drand_beacon_test.go b/core/drand_beacon_test.go index 30d5921d6..1f51afa2b 100644 --- a/core/drand_beacon_test.go +++ b/core/drand_beacon_test.go @@ -21,6 +21,7 @@ import ( func TestBeaconProcess_Stop(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) privs, _ := test.BatchIdentities(1, sch, t.Name()) @@ -36,12 +37,12 @@ func TestBeaconProcess_Stop(t *testing.T) { confOptions = append(confOptions, WithTestDB(t, test.ComputeDBName())...) - dd, err := NewDrandDaemon(NewConfigWithLogger(l, confOptions...)) + dd, err := NewDrandDaemon(ctx, NewConfigWithLogger(l, confOptions...)) require.NoError(t, err) store := test.NewKeyStore() require.NoError(t, store.SaveKeyPair(privs[0])) - proc, err := dd.InstantiateBeaconProcess(t.Name(), store) + proc, err := dd.InstantiateBeaconProcess(ctx, t.Name(), store) require.NoError(t, err) require.NotNil(t, proc) @@ -61,6 +62,7 @@ func TestBeaconProcess_Stop(t *testing.T) { func TestBeaconProcess_Stop_MultiBeaconOneBeaconAlreadyStopped(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) privs, _ := test.BatchIdentities(1, sch, t.Name()) @@ -76,16 +78,16 @@ func TestBeaconProcess_Stop_MultiBeaconOneBeaconAlreadyStopped(t *testing.T) { confOptions = append(confOptions, WithTestDB(t, test.ComputeDBName())...) - dd, err := NewDrandDaemon(NewConfigWithLogger(l, confOptions...)) + dd, err := NewDrandDaemon(ctx, NewConfigWithLogger(l, confOptions...)) require.NoError(t, err) store := test.NewKeyStore() require.NoError(t, store.SaveKeyPair(privs[0])) - proc, err := dd.InstantiateBeaconProcess(t.Name(), store) + proc, err := dd.InstantiateBeaconProcess(ctx, t.Name(), store) require.NoError(t, err) require.NotNil(t, proc) - proc2, err := dd.InstantiateBeaconProcess(t.Name()+"second", store) + proc2, err := dd.InstantiateBeaconProcess(ctx, t.Name()+"second", store) require.NoError(t, err) require.NotNil(t, proc2) diff --git a/core/drand_daemon.go b/core/drand_daemon.go index f380838db..e1096bdf3 100644 --- a/core/drand_daemon.go +++ b/core/drand_daemon.go @@ -6,8 +6,9 @@ import ( "fmt" "sync" - "github.com/drand/drand/dkg" + "go.opentelemetry.io/otel/attribute" + "github.com/drand/drand/dkg" "github.com/drand/drand/chain" "github.com/drand/drand/common" dhttp "github.com/drand/drand/http" @@ -46,10 +47,15 @@ type DrandDaemon struct { } // NewDrandDaemon creates a new instance of DrandDaemon -func NewDrandDaemon(c *Config) (*DrandDaemon, error) { +func NewDrandDaemon(ctx context.Context, c *Config) (*DrandDaemon, error) { + ctx, span := metrics.NewSpan(ctx, "NewDrandDaemon") + defer span.End() + logger := c.Logger() if !c.insecure && (c.certPath == "" || c.keyPath == "") { - return nil, errors.New("config: need to set WithInsecure if no certificate and private key path given") + err := errors.New("config: need to set WithInsecure if no certificate and private key path given") + span.RecordError(err) + return nil, err } drandDaemon := &DrandDaemon{ @@ -64,7 +70,7 @@ func NewDrandDaemon(c *Config) (*DrandDaemon, error) { } // Add callback to register a new handler for http server after finishing DKG successfully - c.dkgCallback = func(share *key.Share, group *key.Group) { + c.dkgCallback = func(ctx context.Context, share *key.Share, group *key.Group) { beaconID := common.GetCanonicalBeaconID(group.ID) drandDaemon.state.Lock() @@ -72,11 +78,11 @@ func NewDrandDaemon(c *Config) (*DrandDaemon, error) { drandDaemon.state.Unlock() if isPresent { - drandDaemon.AddBeaconHandler(beaconID, bp) + drandDaemon.AddBeaconHandler(ctx, beaconID, bp) } } - if err := drandDaemon.init(); err != nil { + if err := drandDaemon.init(ctx); err != nil { return nil, err } @@ -88,6 +94,9 @@ func NewDrandDaemon(c *Config) (*DrandDaemon, error) { } func (dd *DrandDaemon) RemoteStatus(ctx context.Context, request *drand.RemoteStatusRequest) (*drand.RemoteStatusResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.RemoteStatus") + defer span.End() + beaconID, err := dd.readBeaconID(request.Metadata) if err != nil { return nil, err @@ -101,7 +110,10 @@ func (dd *DrandDaemon) RemoteStatus(ctx context.Context, request *drand.RemoteSt return bp.RemoteStatus(ctx, request) } -func (dd *DrandDaemon) init() error { +func (dd *DrandDaemon) init(ctx context.Context) error { + ctx, span := metrics.NewSpan(ctx, "dd.init") + defer span.End() + dd.state.Lock() defer dd.state.Unlock() c := dd.opts @@ -129,12 +141,14 @@ func (dd *DrandDaemon) init() error { handler, err := dhttp.New(ctx, c.Version()) if err != nil { + span.RecordError(err) return err } if pubAddr != "" { if dd.pubGateway, err = net.NewRESTPublicGateway(ctx, pubAddr, c.certPath, c.keyPath, c.certmanager, handler.GetHTTPHandler(), c.insecure); err != nil { + span.RecordError(err) return err } } @@ -150,10 +164,12 @@ func (dd *DrandDaemon) init() error { dd.handler = handler dd.privGateway, err = net.NewGRPCPrivateGateway(ctx, privAddr, c.certPath, c.keyPath, c.certmanager, dd, c.insecure, c.grpcOpts...) if err != nil { + span.RecordError(err) return err } dkgStore, err := dkg.NewDKGStore(c.configFolder, c.boltOpts) if err != nil { + span.RecordError(err) return err } @@ -180,12 +196,16 @@ func (dd *DrandDaemon) init() error { } // InstantiateBeaconProcess creates a new BeaconProcess linked to beacon with id 'beaconID' -func (dd *DrandDaemon) InstantiateBeaconProcess(beaconID string, store key.Store) (*BeaconProcess, error) { +func (dd *DrandDaemon) InstantiateBeaconProcess(ctx context.Context, beaconID string, store key.Store) (*BeaconProcess, error) { + ctx, span := metrics.NewSpan(ctx, "dd.InstantiateBeaconProcess") + defer span.End() + beaconID = common.GetCanonicalBeaconID(beaconID) // we add the BeaconID to our logger's name. Notice the BeaconID never changes. logger := dd.log.Named(beaconID) - bp, err := NewBeaconProcess(logger, store, dd.completedDKGs, beaconID, dd.opts, dd.privGateway, dd.pubGateway) + bp, err := NewBeaconProcess(ctx, logger, store, dd.completedDKGs, beaconID, dd.opts, dd.privGateway, dd.pubGateway) if err != nil { + span.RecordError(err) return nil, err } go bp.StartListeningForDKGUpdates() @@ -203,7 +223,10 @@ func (dd *DrandDaemon) InstantiateBeaconProcess(beaconID string, store key.Store } // RemoveBeaconProcess remove a BeaconProcess linked to beacon with id 'beaconID' -func (dd *DrandDaemon) RemoveBeaconProcess(beaconID string, bp *BeaconProcess) { +func (dd *DrandDaemon) RemoveBeaconProcess(ctx context.Context, beaconID string, bp *BeaconProcess) { + _, span := metrics.NewSpan(ctx, "dd.RemoveBeaconProcess") + defer span.End() + beaconID = common.GetCanonicalBeaconID(beaconID) chainHash := "" @@ -232,7 +255,10 @@ func (dd *DrandDaemon) RemoveBeaconProcess(beaconID string, bp *BeaconProcess) { // AddBeaconHandler adds a handler linked to beacon with chain hash from http server used to // expose public services -func (dd *DrandDaemon) AddBeaconHandler(beaconID string, bp *BeaconProcess) { +func (dd *DrandDaemon) AddBeaconHandler(ctx context.Context, beaconID string, bp *BeaconProcess) { + _, span := metrics.NewSpan(ctx, "dd.AddBeaconHandler") + defer span.End() + chainHash := chain.NewChainInfoWithLogger(dd.log, bp.group).HashString() bh := dd.handler.RegisterNewBeaconHandler(&drandProxy{bp}, chainHash) @@ -252,7 +278,10 @@ func (dd *DrandDaemon) AddBeaconHandler(beaconID string, bp *BeaconProcess) { // RemoveBeaconHandler removes a handler linked to beacon with chain hash from http server used to // expose public services -func (dd *DrandDaemon) RemoveBeaconHandler(beaconID string, bp *BeaconProcess) { +func (dd *DrandDaemon) RemoveBeaconHandler(ctx context.Context, beaconID string, bp *BeaconProcess) { + _, span := metrics.NewSpan(ctx, "dd.RemoveBeaconHandler") + defer span.End() + if bp.group == nil { return } @@ -269,16 +298,23 @@ func (dd *DrandDaemon) RemoveBeaconHandler(beaconID string, bp *BeaconProcess) { // When singleBeacon is set, and the singleBeaconName matches one of the stored beacons, then // only that beacon will be loaded. // If the singleBeaconName is an empty string, no beacon will be loaded. -func (dd *DrandDaemon) LoadBeaconsFromDisk(metricsFlag string, singleBeacon bool, singleBeaconName string) error { +func (dd *DrandDaemon) LoadBeaconsFromDisk(ctx context.Context, metricsFlag string, singleBeacon bool, singleBeaconName string) error { + ctx, span := metrics.NewSpan(ctx, "dd.LoadBeaconsFromDisk") + defer span.End() + // Are we trying to start the daemon without any beacon running? if singleBeacon && singleBeaconName == "" { dd.log.Warnw("starting daemon with no active beacon") + span.SetAttributes( + attribute.Bool("noBeacon", true), + ) return nil } // Load possible existing stores stores, err := key.NewFileStores(dd.opts.ConfigFolderMB()) if err != nil { + span.RecordError(err) return err } @@ -290,8 +326,9 @@ func (dd *DrandDaemon) LoadBeaconsFromDisk(metricsFlag string, singleBeacon bool continue } - bp, err := dd.LoadBeaconFromStore(beaconID, fs) + bp, err := dd.LoadBeaconFromStore(ctx, beaconID, fs) if err != nil { + span.RecordError(err) return err } @@ -315,20 +352,28 @@ func (dd *DrandDaemon) LoadBeaconsFromDisk(metricsFlag string, singleBeacon bool return nil } -func (dd *DrandDaemon) LoadBeaconFromDisk(beaconID string) (*BeaconProcess, error) { +func (dd *DrandDaemon) LoadBeaconFromDisk(ctx context.Context, beaconID string) (*BeaconProcess, error) { + ctx, span := metrics.NewSpan(ctx, "dd.LoadBeaconFromDisk") + defer span.End() + store := key.NewFileStore(dd.opts.ConfigFolderMB(), beaconID) - return dd.LoadBeaconFromStore(beaconID, store) + return dd.LoadBeaconFromStore(ctx, beaconID, store) } -func (dd *DrandDaemon) LoadBeaconFromStore(beaconID string, store key.Store) (*BeaconProcess, error) { - bp, err := dd.InstantiateBeaconProcess(beaconID, store) +func (dd *DrandDaemon) LoadBeaconFromStore(ctx context.Context, beaconID string, store key.Store) (*BeaconProcess, error) { + ctx, span := metrics.NewSpan(ctx, "dd.LoadBeaconFromStore") + defer span.End() + + bp, err := dd.InstantiateBeaconProcess(ctx, beaconID, store) if err != nil { dd.log.Errorw("can't instantiate randomness beacon", "beacon id", beaconID, "err", err) + span.RecordError(err) return nil, err } - status, err := dd.dkg.DKGStatus(context.Background(), &drand.DKGStatusRequest{BeaconID: beaconID}) + status, err := dd.dkg.DKGStatus(ctx, &drand.DKGStatusRequest{BeaconID: beaconID}) if err != nil { + span.RecordError(err) return nil, err } @@ -344,9 +389,12 @@ func (dd *DrandDaemon) LoadBeaconFromStore(beaconID string, store key.Store) (*B dd.log.Infow(fmt.Sprintf("beacon id [%s]: will start running randomness beacon.", beaconID)) // Add beacon handler for http server - dd.AddBeaconHandler(beaconID, bp) + dd.AddBeaconHandler(ctx, beaconID, bp) - err = bp.StartBeacon(true) + err = bp.StartBeacon(ctx, true) + if err != nil { + span.RecordError(err) + } return bp, err } diff --git a/core/drand_daemon_control.go b/core/drand_daemon_control.go index 7ec73429a..8d34c7859 100644 --- a/core/drand_daemon_control.go +++ b/core/drand_daemon_control.go @@ -2,6 +2,7 @@ package core import ( "context" + "errors" "fmt" "time" @@ -14,12 +15,18 @@ import ( // PingPong simply responds with an empty packet, proving that this drand node // is up and alive. func (dd *DrandDaemon) PingPong(ctx context.Context, in *drand.Ping) (*drand.Pong, error) { + _, span := metrics.NewSpan(ctx, "dd.PingPong") + defer span.End() + metadata := common.NewMetadata(dd.version.ToProto()) return &drand.Pong{Metadata: metadata}, nil } // Status responds with the actual status of drand process func (dd *DrandDaemon) Status(ctx context.Context, in *drand.StatusRequest) (*drand.StatusResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.Status") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { return nil, err @@ -28,7 +35,10 @@ func (dd *DrandDaemon) Status(ctx context.Context, in *drand.StatusRequest) (*dr return bp.Status(ctx, in) } -func (dd *DrandDaemon) ListSchemes(ctx context.Context, in *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { +func (dd *DrandDaemon) ListSchemes(ctx context.Context, _ *drand.ListSchemesRequest) (*drand.ListSchemesResponse, error) { + _, span := metrics.NewSpan(ctx, "dd.ListSchemes") + defer span.End() + metadata := common.NewMetadata(dd.version.ToProto()) return &drand.ListSchemesResponse{Ids: crypto.ListSchemes(), Metadata: metadata}, nil @@ -37,6 +47,9 @@ func (dd *DrandDaemon) ListSchemes(ctx context.Context, in *drand.ListSchemesReq // PublicKey is a functionality of Control Service defined in protobuf/control // that requests the long term public key of the drand node running locally func (dd *DrandDaemon) PublicKey(ctx context.Context, in *drand.PublicKeyRequest) (*drand.PublicKeyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.PublicKey") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { return nil, err @@ -48,12 +61,15 @@ func (dd *DrandDaemon) PublicKey(ctx context.Context, in *drand.PublicKeyRequest // PrivateKey is a functionality of Control Service defined in protobuf/control // that requests the long term private key of the drand node running locally // Deprecated: no need to export secret key to a remote client. -func (dd *DrandDaemon) PrivateKey(ctx context.Context, in *drand.PrivateKeyRequest) (*drand.PrivateKeyResponse, error) { +func (dd *DrandDaemon) PrivateKey(context.Context, *drand.PrivateKeyRequest) (*drand.PrivateKeyResponse, error) { return nil, fmt.Errorf("deprecated function: exporting the PrivateKey to a remote client is not supported") } // GroupFile replies with the distributed key in the response func (dd *DrandDaemon) GroupFile(ctx context.Context, in *drand.GroupRequest) (*drand.GroupPacket, error) { + ctx, span := metrics.NewSpan(ctx, "dd.GroupFile") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { return nil, err @@ -64,6 +80,9 @@ func (dd *DrandDaemon) GroupFile(ctx context.Context, in *drand.GroupRequest) (* // Shutdown stops the node func (dd *DrandDaemon) Shutdown(ctx context.Context, in *drand.ShutdownRequest) (*drand.ShutdownResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.Shutdown") + defer span.End() + // If beacon id is empty, we will stop the entire node. Otherwise, we will stop the specific beacon process if in.GetMetadata().GetBeaconID() == "" { dd.Stop(ctx) @@ -78,12 +97,12 @@ func (dd *DrandDaemon) Shutdown(ctx context.Context, in *drand.ShutdownRequest) return nil, err } - dd.RemoveBeaconHandler(beaconID, bp) + dd.RemoveBeaconHandler(ctx, beaconID, bp) bp.Stop(ctx) <-bp.WaitExit() - dd.RemoveBeaconProcess(beaconID, bp) + dd.RemoveBeaconProcess(ctx, beaconID, bp) } metadata := common.NewMetadata(dd.version.ToProto()) @@ -93,6 +112,9 @@ func (dd *DrandDaemon) Shutdown(ctx context.Context, in *drand.ShutdownRequest) // LoadBeacon tells the DrandDaemon to load a new beacon into the memory func (dd *DrandDaemon) LoadBeacon(ctx context.Context, in *drand.LoadBeaconRequest) (*drand.LoadBeaconResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.LoadBeacon") + defer span.End() + beaconID, err := dd.readBeaconID(in.GetMetadata()) if err != nil { return nil, err @@ -103,7 +125,7 @@ func (dd *DrandDaemon) LoadBeacon(ctx context.Context, in *drand.LoadBeaconReque return nil, fmt.Errorf("beacon id [%s] is already running", beaconID) } - _, err = dd.LoadBeaconFromDisk(beaconID) + _, err = dd.LoadBeaconFromDisk(ctx, beaconID) if err != nil { return nil, err } @@ -114,6 +136,9 @@ func (dd *DrandDaemon) LoadBeacon(ctx context.Context, in *drand.LoadBeaconReque // BackupDatabase triggers a backup of the primary database. func (dd *DrandDaemon) BackupDatabase(ctx context.Context, in *drand.BackupDBRequest) (*drand.BackupDBResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.BackupDatabase") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { return nil, err @@ -123,13 +148,16 @@ func (dd *DrandDaemon) BackupDatabase(ctx context.Context, in *drand.BackupDBReq } func (dd *DrandDaemon) StartFollowChain(in *drand.StartSyncRequest, stream drand.Control_StartFollowChainServer) error { + ctx, span := metrics.NewSpan(stream.Context(), "dd.StartFollowChain") + defer span.End() + dd.log.Debugw("StartFollowChain", "requested_chainhash", in.Metadata.ChainHash) bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { return err } - return bp.StartFollowChain(in, stream) + return bp.StartFollowChain(ctx, in, stream) } func (dd *DrandDaemon) StartCheckChain(in *drand.StartSyncRequest, stream drand.Control_StartCheckChainServer) error { @@ -142,7 +170,10 @@ func (dd *DrandDaemon) StartCheckChain(in *drand.StartSyncRequest, stream drand. return bp.StartCheckChain(in, stream) } -func (dd *DrandDaemon) ListBeaconIDs(ctx context.Context, in *drand.ListBeaconIDsRequest) (*drand.ListBeaconIDsResponse, error) { +func (dd *DrandDaemon) ListBeaconIDs(ctx context.Context, _ *drand.ListBeaconIDsRequest) (*drand.ListBeaconIDsResponse, error) { + _, span := metrics.NewSpan(ctx, "dd.ListBeaconIDs") + defer span.End() + metadata := common.NewMetadata(dd.version.ToProto()) dd.state.Lock() @@ -169,10 +200,15 @@ func (dd *DrandDaemon) KeypairFor(beaconID string) (*key.Pair, error) { // Stop simply stops all drand operations. func (dd *DrandDaemon) Stop(ctx context.Context) { + ctx, span := metrics.NewSpan(ctx, "dd.Stop") + defer span.End() + dd.log.Debugw("dd.Stop called") select { case <-dd.exitCh: - dd.log.Errorw("Trying to stop an already stopping daemon") + msg := "trying to stop an already stopping daemon" + dd.log.Errorw(msg) + span.RecordError(errors.New(msg)) return default: dd.log.Infow("Stopping DrandDaemon") @@ -197,6 +233,8 @@ func (dd *DrandDaemon) Stop(ctx context.Context) { } case <-t.C: dd.log.Errorw("beacon process failed to terminate in 5 seconds, exiting forcefully", "id", bp.getBeaconID()) + err := fmt.Errorf("beacon process %q failed to terminate in 5 seconds, exiting forcefully", bp.getBeaconID()) + span.RecordError(err) } } diff --git a/core/drand_daemon_interceptors.go b/core/drand_daemon_interceptors.go index d3a7cc165..bee64b0c0 100644 --- a/core/drand_daemon_interceptors.go +++ b/core/drand_daemon_interceptors.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc/status" commonutils "github.com/drand/drand/common" + "github.com/drand/drand/metrics" "github.com/drand/drand/protobuf/common" ) @@ -18,6 +19,9 @@ type MetadataGetter interface { func (dd *DrandDaemon) NodeVersionValidator(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (response interface{}, err error) { + ctx, span := metrics.NewSpan(ctx, "dd.NodeVersionValidator") + defer span.End() + reqWithContext, ok := req.(MetadataGetter) if !ok { diff --git a/core/drand_daemon_public.go b/core/drand_daemon_public.go index 3b0d99e28..3b1c31293 100644 --- a/core/drand_daemon_public.go +++ b/core/drand_daemon_public.go @@ -3,30 +3,41 @@ package core import ( "context" + "github.com/drand/drand/metrics" "github.com/drand/drand/protobuf/common" "github.com/drand/drand/protobuf/drand" ) // PartialBeacon receives a beacon generation request and answers // with the partial signature from this drand node. -func (dd *DrandDaemon) PartialBeacon(c context.Context, in *drand.PartialBeaconPacket) (*drand.Empty, error) { +func (dd *DrandDaemon) PartialBeacon(ctx context.Context, in *drand.PartialBeaconPacket) (*drand.Empty, error) { + ctx, span := metrics.NewSpan(ctx, "dd.PartialBeacon") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { + span.RecordError(err) return nil, err } - return bp.PartialBeacon(c, in) + partialBeacon, err := bp.PartialBeacon(ctx, in) + span.RecordError(err) + return partialBeacon, err } // PublicRand returns a public random beacon according to the request. If the Round // field is 0, then it returns the last one generated. -func (dd *DrandDaemon) PublicRand(c context.Context, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { +func (dd *DrandDaemon) PublicRand(ctx context.Context, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.DrandDaemon") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { + span.RecordError(err) return nil, err } - return bp.PublicRand(c, in) + return bp.PublicRand(ctx, in) } // PublicRandStream exports a stream of new beacons as they are generated over gRPC @@ -41,6 +52,9 @@ func (dd *DrandDaemon) PublicRandStream(in *drand.PublicRandRequest, stream dran // Home provides the address the local node is listening func (dd *DrandDaemon) Home(c context.Context, in *drand.HomeRequest) (*drand.HomeResponse, error) { + _, span := metrics.NewSpan(c, "dd.Home") + defer span.End() + ctx := common.NewMetadata(dd.version.ToProto()) return &drand.HomeResponse{Metadata: ctx}, nil @@ -48,8 +62,12 @@ func (dd *DrandDaemon) Home(c context.Context, in *drand.HomeRequest) (*drand.Ho // ChainInfo replies with the chain information this node participates to func (dd *DrandDaemon) ChainInfo(ctx context.Context, in *drand.ChainInfoRequest) (*drand.ChainInfoPacket, error) { + ctx, span := metrics.NewSpan(ctx, "dd.ChainInfo") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { + span.RecordError(err) return nil, err } @@ -69,8 +87,12 @@ func (dd *DrandDaemon) SyncChain(in *drand.SyncRequest, stream drand.Protocol_Sy // GetIdentity returns the identity of this drand node func (dd *DrandDaemon) GetIdentity(ctx context.Context, in *drand.IdentityRequest) (*drand.IdentityResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dd.GetIdentity") + defer span.End() + bp, err := dd.getBeaconProcessFromRequest(in.GetMetadata()) if err != nil { + span.RecordError(err) return nil, err } diff --git a/core/drand_daemon_test.go b/core/drand_daemon_test.go index dd13a0315..6f243bd52 100644 --- a/core/drand_daemon_test.go +++ b/core/drand_daemon_test.go @@ -16,6 +16,7 @@ import ( func TestNoPanicWhenDrandDaemonPortInUse(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() // bind a random port on localhost listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err, "Failed to bind port for testing") @@ -30,13 +31,16 @@ func TestNoPanicWhenDrandDaemonPortInUse(t *testing.T) { WithPrivateListenAddress("127.0.0.1:0"), ) + test.Tracer(t, ctx) + // an error is returned during daemon creation instead of panicking - _, err = NewDrandDaemon(config) + _, err = NewDrandDaemon(ctx, config) require.Error(t, err) } func TestDrandDaemon_Stop(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) privs, _ := test.BatchIdentities(1, sch, t.Name()) @@ -52,12 +56,12 @@ func TestDrandDaemon_Stop(t *testing.T) { confOptions = append(confOptions, WithTestDB(t, test.ComputeDBName())...) - dd, err := NewDrandDaemon(NewConfigWithLogger(l, confOptions...)) + dd, err := NewDrandDaemon(ctx, NewConfigWithLogger(l, confOptions...)) require.NoError(t, err) store := test.NewKeyStore() require.NoError(t, store.SaveKeyPair(privs[0])) - proc, err := dd.InstantiateBeaconProcess(t.Name(), store) + proc, err := dd.InstantiateBeaconProcess(ctx, t.Name(), store) require.NoError(t, err) require.NotNil(t, proc) diff --git a/core/drand_test.go b/core/drand_test.go index d49d96b37..1ff9949ef 100644 --- a/core/drand_test.go +++ b/core/drand_test.go @@ -153,6 +153,7 @@ func TestRunDKGLarge(t *testing.T) { // Restart last node and wait catch up // Check beacon still works and length is correct func TestDrandDKGFresh(t *testing.T) { + ctx := context.Background() n := 4 beaconPeriod := 1 * time.Second beaconID := test.GetBeaconIDFromEnv() @@ -179,7 +180,7 @@ func TestDrandDKGFresh(t *testing.T) { dt.CheckBeaconLength(t, restOfNodes, 2) t.Logf("Start last node %s\n", lastNode.addr) - dt.StartDrand(t, lastNode.addr, true, false) + dt.StartDrand(ctx, t, lastNode.addr, true, false) // The catchup process will finish when node gets the previous beacons (1st round) err = dt.WaitUntilRound(t, lastNode, 1) @@ -489,6 +490,7 @@ func TestAbortDKGAndStartANewOne(t *testing.T) { // Check they all have same chain info func TestDrandPublicChainInfo(t *testing.T) { + ctx := context.Background() n := 10 thr := key.DefaultThreshold(n) p := 1 * time.Second @@ -507,7 +509,7 @@ func TestDrandPublicChainInfo(t *testing.T) { for i, node := range dt.nodes { d := node.drand t.Logf("Getting chain info from node %d \n", i) - received, err := client.ChainInfo(d.priv.Public) + received, err := client.ChainInfo(ctx, d.priv.Public) require.NoError(t, err, fmt.Sprintf("addr %s", node.addr)) @@ -892,7 +894,7 @@ func TestDrandFollowChain(t *testing.T) { require.NoError(t, err) } require.NoError(t, err) - defer store.Close(ctx) + defer store.Close() lastB, err := store.Last(ctx) require.NoError(t, err) @@ -999,7 +1001,7 @@ func TestDrandCheckChain(t *testing.T) { t.Logf(" \t\t --> Deleting 4th beacon.\n") err = store.Del(ctx, upTo-1) require.NoError(t, err) - err = store.Close(ctx) + err = store.Close() require.NoError(t, err) t.Logf(" \t\t --> Re-Starting node.\n") @@ -1007,7 +1009,7 @@ func TestDrandCheckChain(t *testing.T) { // Skip why: This call will create a new database connection. // However, for the MemDB engine type, this means we create a new backing array from scratch // thus removing all previous items from memory. At that point, this invalidates the test. - dt.StartDrand(t, dt.nodes[0].addr, true, false) + dt.StartDrand(ctx, t, dt.nodes[0].addr, true, false) t.Logf(" \t\t --> Making sure the beacon is now missing.\n") _, err = client.PublicRand(ctx, rootID, &drand.PublicRandRequest{Round: upTo - 1}) @@ -1129,6 +1131,8 @@ func TestDrandPublicStreamProxy(t *testing.T) { } func TestModifyingGroupFileManuallyDoesNotSegfault(t *testing.T) { + ctx := context.Background() + // set up 3 nodes for a test n := 3 thr := key.DefaultThreshold(n) @@ -1154,7 +1158,7 @@ func TestModifyingGroupFileManuallyDoesNotSegfault(t *testing.T) { require.NoError(t, err) // stop the node and wait for it - node.daemon.Stop(context.Background()) + node.daemon.Stop(ctx) <-node.daemon.exitCh // although the exit channel has signaled exit, the control client is stopped out of band // without waiting the pessimistic closing time, we may try and restart the daemon below @@ -1177,7 +1181,7 @@ func TestModifyingGroupFileManuallyDoesNotSegfault(t *testing.T) { require.NoError(t, err) // try and reload the beacon from the store // the updated TLS status will fail verification - _, err = node.daemon.LoadBeaconFromStore(beaconID, store) + _, err = node.daemon.LoadBeaconFromStore(ctx, beaconID, store) require.EqualError(t, err, "could not restore beacon info for the given identity - this can happen if you updated the group file manually") } diff --git a/core/util_test.go b/core/util_test.go index 29c69cfe0..bf78914f4 100644 --- a/core/util_test.go +++ b/core/util_test.go @@ -21,6 +21,7 @@ import ( "github.com/drand/drand/common" "github.com/drand/drand/crypto" "github.com/drand/drand/key" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/drand" "github.com/drand/drand/test" @@ -69,7 +70,7 @@ type DrandTestScenario struct { // client that can reach any drand node. // Deprecated: do not use // -//nolint:funlen +//nolint:funlen // This is a test function func BatchNewDrand( t *testing.T, currentNodeCount, @@ -130,6 +131,11 @@ func BatchNewDrand( l := testlogger.New(t) for i := 0; i < n; i++ { + ctx := context.Background() + + tracer := test.TracerWithName(t, ctx, ports[i]) + ctx, span := tracer.Start(ctx, "TestBatchNewDrand") + s := test.NewKeyStore() require.NoError(t, s.SaveKeyPair(privs[i])) @@ -163,12 +169,14 @@ func BatchNewDrand( t.Logf("Creating node %d\n", i) - daemon, err := NewDrandDaemon(NewConfigWithLogger(l, confOptions...)) + daemon, err := NewDrandDaemon(ctx, NewConfigWithLogger(l, confOptions...)) require.NoError(t, err) - bp, err := daemon.InstantiateBeaconProcess(beaconID, s) + bp, err := daemon.InstantiateBeaconProcess(ctx, beaconID, s) require.NoError(t, err) + span.End() + daemons[i] = daemon drands[i] = bp @@ -240,7 +248,7 @@ func (d *DrandTestScenario) Ids(n int, newGroup bool) []string { } // GetBeacon returns the beacon of the given round for the specified drand id -func (d *DrandTestScenario) GetBeacon(id string, round int, newGroup bool) (*chain.Beacon, error) { +func (d *DrandTestScenario) GetBeacon(ctx context.Context, id string, round int, newGroup bool) (*chain.Beacon, error) { nodes := d.nodes if newGroup { nodes = d.resharedNodes @@ -249,7 +257,7 @@ func (d *DrandTestScenario) GetBeacon(id string, round int, newGroup bool) (*cha if node.addr != id { continue } - return node.drand.beacon.Store().Get(context.Background(), uint64(round)) + return node.drand.beacon.Store().Get(ctx, uint64(round)) } return nil, errors.New("that should not happen") } @@ -306,12 +314,12 @@ func (d *DrandTestScenario) StopMockNode(nodeAddr string, newGroup bool) { // StartDrand fetches the drand given the id, in the respective group given the // newGroup parameter and runs the beacon -func (d *DrandTestScenario) StartDrand(t *testing.T, nodeAddress string, catchup, newGroup bool) { +func (d *DrandTestScenario) StartDrand(ctx context.Context, t *testing.T, nodeAddress string, catchup, newGroup bool) { node := d.GetMockNode(nodeAddress, newGroup) dr := node.drand d.t.Log("[drand] Start") - err := dr.StartBeacon(catchup) + err := dr.StartBeacon(ctx, catchup) require.NoError(t, err) d.t.Log("[drand] Started") } diff --git a/demo/main.go b/demo/main.go index de0a7a5e4..d5094525d 100644 --- a/demo/main.go +++ b/demo/main.go @@ -37,6 +37,7 @@ var dbEngineType = flag.String("dbtype", "bolt", "Which database engine to use. func main() { flag.Parse() + if *build { installDrand() } diff --git a/demo/node/node_inprocess.go b/demo/node/node_inprocess.go index 9ddee28fc..1807b0ccb 100644 --- a/demo/node/node_inprocess.go +++ b/demo/node/node_inprocess.go @@ -107,6 +107,8 @@ func NewLocalNode(i int, bindAddr string, cfg cfg.Config) *LocalNode { } func (l *LocalNode) Start(certFolder string, dbEngineType chain.StorageType, pgDSN func() string, memDBSize int) error { + ctx := context.Background() + if dbEngineType != "" { l.dbEngineType = dbEngineType } @@ -154,7 +156,7 @@ func (l *LocalNode) Start(certFolder string, dbEngineType chain.StorageType, pgD } // Create and start drand daemon - drandDaemon, err := core.NewDrandDaemon(conf) + drandDaemon, err := core.NewDrandDaemon(ctx, conf) if err != nil { return fmt.Errorf("can't instantiate drand daemon %s", err) } @@ -166,13 +168,14 @@ func (l *LocalNode) Start(certFolder string, dbEngineType chain.StorageType, pgD } for beaconID, ks := range stores { - bp, err := drandDaemon.InstantiateBeaconProcess(beaconID, ks) + ctx := context.Background() + bp, err := drandDaemon.InstantiateBeaconProcess(ctx, beaconID, ks) if err != nil { fmt.Printf("beacon id [%s]: can't instantiate randomness beacon. err: %s \n", beaconID, err) return err } - err = bp.Load() + err = bp.Load(ctx) isFreshRun := err == core.ErrDKGNotStarted if err != nil && !isFreshRun { return err @@ -182,13 +185,13 @@ func (l *LocalNode) Start(certFolder string, dbEngineType chain.StorageType, pgD } else { fmt.Printf("beacon id [%s]: will already start running randomness beacon.\n", beaconID) // Add beacon handler from chain hash for http server - drandDaemon.AddBeaconHandler(beaconID, bp) + drandDaemon.AddBeaconHandler(ctx, beaconID, bp) // XXX make it configurable so that new share holder can still start if // nobody started. // drand.StartBeacon(!c.Bool(pushFlag.Name)) catchup := true - err = bp.StartBeacon(catchup) + err = bp.StartBeacon(ctx, catchup) if err != nil { return err } diff --git a/devenv/conf/grafana/provisioning/datasources/datasources.yaml b/devenv/conf/grafana/provisioning/datasources/datasources.yaml new file mode 100644 index 000000000..edd58dab9 --- /dev/null +++ b/devenv/conf/grafana/provisioning/datasources/datasources.yaml @@ -0,0 +1,49 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://drand_dev_prometheus:9090 + jsonData: + httpMethod: POST + prometheusType: Prometheus + prometheusVersion: 2.42.0 + + - name: Loki + type: loki + access: proxy + url: http://drand_dev_loki:3100 + jsonData: + maxLines: 1000 + + - name: Tempo + type: tempo + access: proxy + isDefault: true + url: http://drand_dev_tempo:3200 + jsonData: + httpMethod: GET + tracesToLogs: + datasourceUid: 'Loki' + tags: ['job', 'instance', 'pod', 'namespace'] + mappedTags: [{ key: 'service.name', value: 'service' }] + mapTagNamesEnabled: false + spanStartTimeShift: '1h' + spanEndTimeShift: '1h' + filterByTraceID: true + filterBySpanID: true + tracesToMetrics: + datasourceUid: 'Prometheus' + tags: [{ key: 'service.name', value: 'service' }, { key: 'job' }] + queries: + - name: 'Query' + query: 'sum(rate(traces_spanmetrics_latency_bucket{$__tags}[5m]))' + serviceMap: + datasourceUid: 'Prometheus' + search: + hide: false + nodeGraph: + enabled: true + lokiSearch: + datasourceUid: 'Loki' diff --git a/devenv/conf/loki.yaml b/devenv/conf/loki.yaml new file mode 100644 index 000000000..4450d858c --- /dev/null +++ b/devenv/conf/loki.yaml @@ -0,0 +1,40 @@ +analytics: + reporting_enabled: false + +auth_enabled: false + +server: + http_listen_port: 3100 + +ingester: + lifecycler: + address: 127.0.0.1 + ring: + kvstore: + store: inmemory + replication_factor: 1 + final_sleep: 0s + chunk_idle_period: 5m + chunk_retain_period: 30s + +schema_config: + configs: + - from: 2020-05-15 + store: boltdb + object_store: filesystem + schema: v11 + index: + prefix: index_ + period: 168h + +storage_config: + boltdb: + directory: /tmp/loki/index + + filesystem: + directory: /tmp/loki/chunks + +limits_config: + enforce_metric_name: false + reject_old_samples: true + reject_old_samples_max_age: 168h diff --git a/devenv/conf/prom.yaml b/devenv/conf/prom.yaml new file mode 100644 index 000000000..65548de7a --- /dev/null +++ b/devenv/conf/prom.yaml @@ -0,0 +1,29 @@ +# my global config +global: + scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. + evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. + scrape_timeout: 10s # is set to the global default (10s). + +# Alertmanager configuration +alerting: + alertmanagers: + - static_configs: + - targets: + - alertmanager:9093 + +# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. +rule_files: +# - "first_rules.yml" +# - "second_rules.yml" + +# A scrape configuration containing exactly one endpoint to scrape: +# Here it's Prometheus itself. +scrape_configs: +# The job name is added as a label `job=` to any timeseries scraped from this config. +# - job_name: "prometheus" +# +# # metrics_path defaults to '/metrics' +# # scheme defaults to 'http'. +# +# static_configs: +# - targets: [ "localhost:9090" ] diff --git a/devenv/conf/tempo.yaml b/devenv/conf/tempo.yaml new file mode 100644 index 000000000..6fb7c16c7 --- /dev/null +++ b/devenv/conf/tempo.yaml @@ -0,0 +1,62 @@ +usage_report: + reporting_enabled: false + +server: + http_listen_port: 3200 + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + grpc: + opencensus: + +ingester: + trace_idle_period: 10s # the length of time after a trace has not received spans to consider it complete and flush it + max_block_bytes: 1_000_000 # cut the head block when it hits this size or ... + max_block_duration: 5m # this much time passes + +compactor: + compaction: + compaction_window: 1h # blocks in this time window will be compacted together + max_block_bytes: 100_000_000 # maximum size of compacted blocks + block_retention: 1h + compacted_block_retention: 10m + +metrics_generator: + registry: + external_labels: + source: tempo + cluster: docker-compose + storage: + path: /tmp/tempo/generator/wal + remote_write: + - url: http://prometheus:9090/api/v1/write + send_exemplars: true + +storage: + trace: + backend: local # backend configuration to use + block: + bloom_filter_false_positive: .05 # bloom filter false positive rate. lower values create larger filters but fewer false positives + v2_index_downsample_bytes: 1000 # number of bytes per index record + v2_encoding: zstd # block encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2 + wal: + path: /tmp/tempo/wal # where to store the the wal locally + v2_encoding: snappy # wal encoding/compression. options: none, gzip, lz4-64k, lz4-256k, lz4-1M, lz4, snappy, zstd, s2 + local: + path: /tmp/tempo/blocks + pool: + max_workers: 100 # worker pool determines the number of parallel requests to the object store backend + queue_depth: 10000 + +overrides: + metrics_generator_processors: [ service-graphs, span-metrics ] diff --git a/devenv/docker-compose.yaml b/devenv/docker-compose.yaml new file mode 100644 index 000000000..dc8edab6e --- /dev/null +++ b/devenv/docker-compose.yaml @@ -0,0 +1,86 @@ +version: "3.8" + +name: "drand_dev" + +configs: + prom_conf: + file: ./conf/prom.yaml + loki_conf: + file: ./conf/loki.yaml + tempo_conf: + file: ./conf/tempo.yaml + +services: + postgres: + hostname: "drand_dev_postgres" + image: postgres:15.1-alpine3.16 + environment: + - POSTGRES_USER=drand + - POSTGRES_PASSWORD=drand + - POSTGRES_DB=drand + ports: + - 5432:5432 + + prometheus: + hostname: "drand_dev_prometheus" + image: prom/prometheus:v2.42.0 + command: + - "--config.file=/prom_conf" + - "--storage.tsdb.path=/prometheus/" + configs: + - prom_conf + ports: + - 9090:9090 + + tempo: + hostname: "drand_dev_tempo" + image: grafana/tempo:2.0.1 + environment: + - TERM=linux + command: + - -config.file=/tempo_conf + ports: + - 14268:14268 + - 3200:3200 + - 4317:4317 + - 4318:4318 + - 9411:9411 + configs: + - tempo_conf + depends_on: + - prometheus + + loki: + hostname: "drand_dev_loki" + image: grafana/loki:2.7.4 + configs: + - loki_conf + environment: + - TERM=linux + command: + - -config.file=/loki_conf + ports: + - 3100:3100 + tmpfs: + - /wal + + grafana: + hostname: "drand_dev_grafana" + image: grafana/grafana:9.4.3 + environment: + - TERM=linux + - GF_ANALYTICS_REPORTING_ENABLED='false' + - GF_ANALYTICS_CHECK_FOR_UPDATES='false' + - GF_ANALYTICS_CHECK_FOR_PLUGIN_UPDATES='false' + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE='traceqlEditor' + volumes: + - ./conf/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources/ + ports: + - 3000:3000 + depends_on: + - prometheus + - loki + - tempo diff --git a/dkg/broadcast.go b/dkg/broadcast.go index e82e32598..7158a8ff3 100644 --- a/dkg/broadcast.go +++ b/dkg/broadcast.go @@ -8,16 +8,16 @@ import ( "math/rand" "sync" - "github.com/drand/drand/crypto" - - "github.com/drand/drand/util" + oteltrace "go.opentelemetry.io/otel/trace" "github.com/drand/drand/protobuf/common" pdkg "github.com/drand/drand/protobuf/crypto/dkg" "github.com/drand/kyber" - + "github.com/drand/drand/crypto" + "github.com/drand/drand/util" commonutils "github.com/drand/drand/common" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/drand" "github.com/drand/kyber/share/dkg" @@ -28,7 +28,7 @@ import ( // implement the broadcasting mechanism. type Broadcast interface { dkg.Board - BroadcastDKG(c context.Context, p *drand.DKGPacket) error + BroadcastDKG(ctx context.Context, p *drand.DKGPacket) error Stop() } @@ -53,6 +53,7 @@ type Broadcast interface { // of the node don't accept it because it's too late. Note that even though the // DKG library allows to use fast sync the fast sync mode. type echoBroadcast struct { + ctx context.Context sync.Mutex l log.Logger version commonutils.Version @@ -74,7 +75,8 @@ type packet = dkg.Packet var _ Broadcast = (*echoBroadcast)(nil) func newEchoBroadcast( - client net.DKGClient, + ctx context.Context, +client net.DKGClient, l log.Logger, version commonutils.Version, beaconID string, @@ -89,10 +91,11 @@ func newEchoBroadcast( // copy the config to avoid races c := *config return &echoBroadcast{ + ctx: ctx, l: l.Named("echoBroadcast"), version: version, beaconID: beaconID, - dispatcher: newDispatcher(client, l, to, own), + dispatcher: newDispatcher(ctx, client, l, to, own), dealCh: make(chan dkg.DealBundle, len(to)), respCh: make(chan dkg.ResponseBundle, len(to)), justCh: make(chan dkg.JustificationBundle, len(to)), @@ -104,41 +107,55 @@ func newEchoBroadcast( } func (b *echoBroadcast) PushDeals(bundle *dkg.DealBundle) { + ctx, span := metrics.NewSpan(b.ctx, "b.PushDeals") + defer span.End() + b.dealCh <- *bundle b.Lock() defer b.Unlock() h := hash(bundle.Hash()) b.l.Infow("push broadcast", "deal", fmt.Sprintf("%x", h[:5])) - b.sendout(h, bundle, true, b.beaconID) + b.sendout(ctx, h, bundle, true, b.beaconID) } func (b *echoBroadcast) PushResponses(bundle *dkg.ResponseBundle) { + ctx, span := metrics.NewSpan(b.ctx, "b.PushResponses") + defer span.End() + b.respCh <- *bundle b.Lock() defer b.Unlock() h := hash(bundle.Hash()) b.l.Debugw("push", "response", bundle.String()) - b.sendout(h, bundle, true, b.beaconID) + b.sendout(ctx, h, bundle, true, b.beaconID) } func (b *echoBroadcast) PushJustifications(bundle *dkg.JustificationBundle) { + ctx, span := metrics.NewSpan(b.ctx, "b.PushJustifications") + defer span.End() + b.justCh <- *bundle b.Lock() defer b.Unlock() h := hash(bundle.Hash()) b.l.Debugw("push", "justification", fmt.Sprintf("%x", h[:5])) - b.sendout(h, bundle, true, b.beaconID) + b.sendout(ctx, h, bundle, true, b.beaconID) } -func (b *echoBroadcast) BroadcastDKG(c context.Context, p *drand.DKGPacket) error { +func (b *echoBroadcast) BroadcastDKG(ctx context.Context, p *drand.DKGPacket) error { + ctx, span := metrics.NewSpan(ctx, "b.BroadcastDKG") + defer span.End() + b.Lock() defer b.Unlock() - addr := net.RemoteAddress(c) + addr := net.RemoteAddress(ctx) dkgPacket, err := protoToDKGPacket(p.GetDkg(), b.scheme) if err != nil { b.l.Errorw("received invalid packet DKGPacket", "from", addr, "err", err) - return errors.New("invalid DKGPacket") + err := errors.New("invalid DKGPacket") + span.RecordError(err) + return err } hash := hash(dkgPacket.Hash()) @@ -152,11 +169,13 @@ func (b *echoBroadcast) BroadcastDKG(c context.Context, p *drand.DKGPacket) erro dkgConfig := b.config if err := dkg.VerifyPacketSignature(&dkgConfig, dkgPacket); err != nil { b.l.Errorw("received invalid signature", "from", addr, "signature", dkgPacket.Sig(), "scheme", b.scheme, "err", err) - return errors.New("invalid DKGPacket") + err := errors.New("invalid DKGPacket") + span.RecordError(err) + return err } b.l.Debugw("received new packet to echoBroadcast", "from", addr, "packet index", dkgPacket.Index(), "type", fmt.Sprintf("%T", dkgPacket)) - b.sendout(hash, dkgPacket, false, b.beaconID) // we're using the rate limiting + b.sendout(ctx, hash, dkgPacket, false, b.beaconID) // we're using the rate limiting b.passToApplication(dkgPacket) return nil } @@ -178,7 +197,10 @@ func (b *echoBroadcast) passToApplication(p packet) { // so it is broadcasted out to all nodes. sendout requires the echoBroadcast // lock. If bypass is true, the message is directly sent to the peers, bypassing // the rate limiting in place. -func (b *echoBroadcast) sendout(h []byte, p packet, bypass bool, beaconID string) { +func (b *echoBroadcast) sendout(ctx context.Context, h []byte, p packet, bypass bool, beaconID string) { + _, span := metrics.NewSpan(ctx, "b.sendout") + defer span.End() + if b.isStopped { return } @@ -196,9 +218,9 @@ func (b *echoBroadcast) sendout(h []byte, p packet, bypass bool, beaconID string // in a routine cause we don't want to block the processing of the DKG // as well - that's ok since we are only expecting to send 3 packets out // at most. - go b.dispatcher.broadcastDirect(proto) + go b.dispatcher.broadcastDirect(span.SpanContext(), proto) } else { - b.dispatcher.broadcast(proto) + b.dispatcher.broadcast(span.SpanContext(), proto) } } @@ -276,7 +298,10 @@ type dispatcher struct { senders []*sender } -func newDispatcher(dkgClient net.DKGClient, l log.Logger, to []*drand.Participant, us string) *dispatcher { +func newDispatcher(ctx context.Context, dkgClient net.DKGClient, l log.Logger, to []*drand.Participant, us string) *dispatcher { + _, span := metrics.NewSpan(ctx, "newDispatcher") + defer span.End() + var senders = make([]*sender, 0, len(to)-1) queue := senderQueueSize(len(to)) for _, node := range to { @@ -284,7 +309,7 @@ func newDispatcher(dkgClient net.DKGClient, l log.Logger, to []*drand.Participan continue } sender := newSender(dkgClient, node, l, queue) - go sender.run() + go sender.run(span.SpanContext()) senders = append(senders, sender) } return &dispatcher{ @@ -294,17 +319,23 @@ func newDispatcher(dkgClient net.DKGClient, l log.Logger, to []*drand.Participan // broadcast uses the regular channel limitation for messages coming from other // nodes. -func (d *dispatcher) broadcast(p broadcastPacket) { +func (d *dispatcher) broadcast(octx oteltrace.SpanContext, p broadcastPacket) { + ctx, span := metrics.NewSpanFromSpanContext(context.Background(), octx, "d.broadcast") + defer span.End() + for _, i := range rand.Perm(len(d.senders)) { - d.senders[i].sendPacket(p) + d.senders[i].sendPacket(ctx, p) } } // broadcastDirect directly send to the other peers - it is used only for our // own packets so we're not bound to congestion events. -func (d *dispatcher) broadcastDirect(p broadcastPacket) { +func (d *dispatcher) broadcastDirect(octx oteltrace.SpanContext, p broadcastPacket) { + _, span := metrics.NewSpanFromSpanContext(context.Background(), octx, "d.broadcastDirect") + defer span.End() + for _, i := range rand.Perm(len(d.senders)) { - d.senders[i].sendDirect(p) + d.senders[i].sendDirect(span.SpanContext(), p) } } @@ -330,7 +361,10 @@ func newSender(client net.DKGClient, to *drand.Participant, l log.Logger, queueS } } -func (s *sender) sendPacket(p broadcastPacket) { +func (s *sender) sendPacket(ctx context.Context, p broadcastPacket) { + _, span := metrics.NewSpan(ctx, "s.sendPacket") + defer span.End() + select { case s.newCh <- p: default: @@ -338,15 +372,21 @@ func (s *sender) sendPacket(p broadcastPacket) { } } -func (s *sender) run() { +func (s *sender) run(sctx oteltrace.SpanContext) { + _, span := metrics.NewSpanFromSpanContext(context.Background(), sctx, "s.run") + defer span.End() + for newPacket := range s.newCh { - s.sendDirect(newPacket) + s.sendDirect(span.SpanContext(), newPacket) } } -func (s *sender) sendDirect(newPacket broadcastPacket) { +func (s *sender) sendDirect(sctx oteltrace.SpanContext, newPacket broadcastPacket) { + ctx, span := metrics.NewSpanFromSpanContext(context.Background(), sctx, "s.sendDirect") + defer span.End() + node := util.ToPeer(s.to) - _, err := s.client.BroadcastDKG(context.Background(), node, newPacket) + _, err := s.client.BroadcastDKG(ctx, node, newPacket) if err != nil { s.l.Errorw("error while sending out", "to", s.to.Address, "err:", err) } else { diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..32486e14b --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,18 @@ +version: "3.8" +services: + jaeger: + image: jaegertracing/all-in-one:1.38.1 + environment: + - COLLECTOR_ZIPKIN_HOST_PORT=:9411 + - COLLECTOR_OTLP_ENABLED=true + ports: + - 6831:6831/udp + - 6832:6832/udp + - 5778:5778 + - 16686:16686 + - 4317:4317 + - 4318:4318 + - 14250:14250 + - 14268:14268 + - 14269:14269 + - 9411:9411 diff --git a/go.mod b/go.mod index af76e475f..410018d5b 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,9 @@ go 1.19 require ( github.com/BurntSushi/toml v1.2.1 - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/ardanlabs/darwin/v2 v2.0.0 - github.com/aws/aws-sdk-go v1.44.196 - github.com/benbjohnson/clock v1.3.0 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/briandowns/spinner v1.21.0 + github.com/aws/aws-sdk-go v1.44.211 + github.com/briandowns/spinner v1.22.0 github.com/drand/kyber v1.1.18 github.com/drand/kyber-bls12381 v0.2.5 github.com/go-chi/chi v1.5.4 @@ -19,34 +16,51 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/golang-lru v0.5.4 + github.com/hashicorp/golang-lru v0.5.1 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jmoiron/sqlx v1.3.5 github.com/jonboulle/clockwork v0.3.0 github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 github.com/lib/pq v1.10.7 - github.com/libp2p/go-libp2p v0.24.2 - github.com/libp2p/go-libp2p-pubsub v0.8.3 + github.com/libp2p/go-libp2p v0.26.1 + github.com/libp2p/go-libp2p-pubsub v0.9.1 github.com/multiformats/go-multiaddr v0.8.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/nikkolasg/hexjson v0.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 - github.com/rogpeppe/go-internal v1.9.1-0.20230118214834-e3815afac6ff - github.com/stretchr/testify v1.8.1 - github.com/urfave/cli/v2 v2.20.1 + github.com/rogpeppe/go-internal v1.9.0 + github.com/stretchr/testify v1.8.2 + github.com/urfave/cli/v2 v2.24.4 github.com/weaveworks/common v0.0.0-20230208133027-16871410fca4 go.etcd.io/bbolt v1.3.7 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 + go.opentelemetry.io/otel v1.14.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 + go.opentelemetry.io/otel/sdk v1.14.0 + go.opentelemetry.io/otel/trace v1.14.0 go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.5.0 + golang.org/x/crypto v0.6.0 golang.org/x/net v0.7.0 golang.org/x/sys v0.5.0 - google.golang.org/grpc v1.52.0 + google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.28.1 ) +//nolint:gomoddirectives // Without this replace, the project cannot compile +replace google.golang.org/grpc => google.golang.org/grpc v1.52.0 + +//nolint:gomoddirectives // Without this replace, urfave/cli will have race conditions +replace github.com/urfave/cli/v2 => github.com/urfave/cli/v2 v2.19.3 + require ( + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect @@ -61,13 +75,14 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.14.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -78,54 +93,52 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect + github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/huin/goupnp v1.0.3 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect + github.com/huin/goupnp v1.1.0 // indirect github.com/ipfs/go-cid v0.3.2 // indirect - github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.2.3 // indirect - github.com/koron/go-ssdp v0.0.3 // indirect + github.com/klauspost/compress v1.16.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-openssl v0.1.0 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.0 // indirect - github.com/lucas-clemente/quic-go v0.31.1 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - github.com/mattn/go-pointer v0.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.50 // indirect + github.com/miekg/dns v1.1.51 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.8.0 // indirect + github.com/multiformats/go-multicodec v0.8.1 // indirect github.com/multiformats/go-multihash v0.2.1 // indirect - github.com/multiformats/go-multistream v0.3.3 // indirect + github.com/multiformats/go-multistream v0.4.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.8.0 // indirect + github.com/onsi/ginkgo/v2 v2.8.4 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect @@ -133,13 +146,17 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/common v0.40.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-19 v0.2.1 // indirect + github.com/quic-go/qtls-go1-20 v0.1.1 // indirect + github.com/quic-go/quic-go v0.33.0 // indirect + github.com/quic-go/webtransport-go v0.5.2 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sercand/kuberesolver v2.4.0+incompatible // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect @@ -147,17 +164,22 @@ require ( github.com/weaveworks/promrus v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect + go.dedis.ch/protobuf v1.0.11 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect + go.opentelemetry.io/otel/metric v0.37.0 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/dig v1.16.1 // indirect - go.uber.org/fx v1.19.1 // indirect + go.uber.org/fx v1.19.2 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect + golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect - golang.org/x/tools v0.5.0 // indirect - google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.1.7 // indirect + nhooyr.io/websocket v1.8.7 // indirect ) diff --git a/go.sum b/go.sum index ff9e6cd38..e64f13ea1 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= @@ -30,31 +29,340 @@ cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Ud cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= @@ -87,8 +395,8 @@ github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfK github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.196 h1:e3h9M7fpnRHwHOohYmYjgVbcCBvkxKwZiT7fGrxRn28= -github.com/aws/aws-sdk-go v1.44.196/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzHK4= +github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -97,9 +405,11 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/briandowns/spinner v1.21.0 h1:2lVBzf3iZ3cT/ulVXljc4BzlL3yTWZDzsGsamI7si+A= -github.com/briandowns/spinner v1.21.0/go.mod h1:TcwZHb7Wb6vn/+bcVv1UXEzaA4pLS7yznHlkY/HzH44= +github.com/briandowns/spinner v1.22.0 h1:fJ/7tyeM2q9ebM57kGfjnUSrgPJBsULk+/s61UpMGrw= +github.com/briandowns/spinner v1.22.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -111,13 +421,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -170,19 +474,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -196,6 +489,10 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= @@ -215,12 +512,29 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -244,8 +558,6 @@ github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0L github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= @@ -294,6 +606,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -318,14 +631,16 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -335,6 +650,8 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= @@ -342,8 +659,8 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= @@ -352,6 +669,9 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -359,13 +679,14 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4= +github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= +github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -382,9 +703,6 @@ github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKn github.com/ipfs/go-ds-badger2 v0.1.3/go.mod h1:TPhhljfrgewjbtuL/tczP8dNrBYwwk+SdPYbms/NO9w= github.com/ipfs/go-ds-leveldb v0.5.0 h1:s++MEBbD3ZKc9/8/njrn4flZLnCuY9I79v94gBUNumo= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= -github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= -github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= @@ -407,8 +725,10 @@ github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQy github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -422,18 +742,19 @@ github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhd github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= -github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -444,6 +765,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -453,12 +776,12 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.24.2 h1:iMViPIcLY0D6zr/f+1Yq9EavCZu2i7eDstsr1nEwSAk= -github.com/libp2p/go-libp2p v0.24.2/go.mod h1:WuxtL2V8yGjam03D93ZBC19tvOUiPpewYv1xdFGWu1k= -github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= -github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= -github.com/libp2p/go-libp2p-pubsub v0.8.3 h1:T4+pcfcFm1K2v5oFyk68peSjVroaoM8zFygf6Y5WOww= -github.com/libp2p/go-libp2p-pubsub v0.8.3/go.mod h1:eje970FXxjhtFbVEoiae+VUw24ZoSlk67BsiZPLRzlw= +github.com/libp2p/go-libp2p v0.26.1 h1:I9bHj5KteIB1tsBWLT25TTttx5xSjun3ph/q/8Xax/k= +github.com/libp2p/go-libp2p v0.26.1/go.mod h1:HKQUKIQ5NhzabNMWq9Wczcs5Ksdx4LQ/ISAq4MRqBHQ= +github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= +github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-pubsub v0.9.1 h1:A6LBg9BaoLf3NwRz+E974sAxTVcbUZYg95IhK2BZz9g= +github.com/libp2p/go-libp2p-pubsub v0.9.1/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= @@ -467,38 +790,25 @@ github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= -github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= -github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4= -github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= -github.com/marten-seemann/qtls-go1-18 v0.1.4 h1:ogomB+lWV3Vmwiu6RTwDVTMGx+9j7SEi98e8QB35Its= -github.com/marten-seemann/qtls-go1-18 v0.1.4/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.2 h1:ZevAEqKXH0bZmoOBPiqX2h5rhQ7cbZi+X+rlq2JUbCE= -github.com/marten-seemann/qtls-go1-19 v0.1.2/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -github.com/marten-seemann/webtransport-go v0.4.3 h1:vkt5o/Ci+luknRteWdYGYH1KcB7ziup+J+1PzZJIvmg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= -github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -507,8 +817,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo= +github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -522,9 +832,11 @@ github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= @@ -543,13 +855,13 @@ github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/e github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= -github.com/multiformats/go-multicodec v0.8.0 h1:evBmgkbSQux+Ds2IgfhkO38Dl2GDtRW8/Rp6YiSHX/Q= -github.com/multiformats/go-multicodec v0.8.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= +github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= +github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= -github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= -github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= +github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= +github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= @@ -560,9 +872,9 @@ github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nikkolasg/hexjson v0.1.0 h1:Cgi1MSZVQFoJKYeRpBNEcdF3LB+Zo4fYKsDz7h8uJYQ= github.com/nikkolasg/hexjson v0.1.0/go.mod h1:fbGbWFZ0FmJMFbpCMtJpwb0tudVxSSZ+Es2TsCg57cA= -github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= -github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU= -github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= +github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0= +github.com/onsi/ginkgo/v2 v2.8.4/go.mod h1:427dEDQZkDKsBvCjc2A/ZPefhKxsTTrsQegMlayL730= +github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= @@ -605,8 +917,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= -github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= +github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q= +github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE= github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -617,12 +929,22 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= +github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= +github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= +github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= +github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= +github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.1-0.20230118214834-e3815afac6ff h1:8sKK+bDq41BDdR3Twlwv4ufZm3+N/hmnb0QkyocX9G0= -github.com/rogpeppe/go-internal v1.9.1-0.20230118214834-e3815afac6ff/go.mod h1:4DOBFiuQsmS6qjl8rsAMyM0e8miaqS/Wnm+9jQ5RiOU= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -661,8 +983,6 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -685,8 +1005,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= @@ -695,10 +1015,14 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMW github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.20.1 h1:WmgYOO0jTw7LaYw71ZZEBNZzPJvzMhmkl8LtR0v0xNo= -github.com/urfave/cli/v2 v2.20.1/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.19.3 h1:GsJ5D2qZWF6hk/F276qqf8v/Ff4IzAUTB+CUFSNhN6M= +github.com/urfave/cli/v2 v2.19.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/weaveworks/common v0.0.0-20230208133027-16871410fca4 h1:8eoXaryYVOWJZCnCzULYXtxiHHLrJpvoD7p283ogmo8= @@ -727,7 +1051,27 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 h1:5jD3teb4Qh7mx/nfzq4jO2WFFpvXD0vYWFDrdvNWmXk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0/go.mod h1:UMklln0+MRhZC4e3PwmN3pCtq4DyIadWw4yikh6bNrw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 h1:lE9EJyw3/JhrjWH/hEy9FptnalDQgj7vpbgC2KCCCxE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0/go.mod h1:pcQ3MM3SWvrA71U4GDqv9UFDJ3HQsW7y5ZO3tDTlUdI= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= +go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= +go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -736,10 +1080,10 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= -go.uber.org/fx v1.19.1 h1:JwYIYAQzXBuBBwSZ1/tn/95pnQO/Sp3yE8lWj9eSAzI= -go.uber.org/fx v1.19.1/go.mod h1:bGK+AEy7XUwTBkqCsK/vDyFF0JJOA6X5KWpNC0e6qTA= +go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= +go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -747,7 +1091,6 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= @@ -767,8 +1110,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -782,13 +1125,11 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= -golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= +golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -812,10 +1153,10 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -858,7 +1199,6 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -866,10 +1206,15 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -894,7 +1239,12 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -909,17 +1259,16 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -938,6 +1287,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -992,6 +1342,8 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -999,11 +1351,15 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1015,7 +1371,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1023,11 +1381,9 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1082,10 +1438,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1136,10 +1492,20 @@ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/S google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1147,9 +1513,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= @@ -1227,49 +1593,39 @@ google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 h1:vArvWooPH749rNHpBGgVl+U9B9dATjiEhJzcWGlovNs= -google.golang.org/genproto v0.0.0-20230202175211-008b39050e57/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514 h1:rtNKfB++wz5mtDY2t5C8TXlU5y52ojSu7tZo0z7u8eQ= +google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk= google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1312,7 +1668,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1322,6 +1677,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/http/server.go b/http/server.go index be9bf6a45..2e5dd61dd 100644 --- a/http/server.go +++ b/http/server.go @@ -15,6 +15,7 @@ import ( "github.com/go-chi/chi" json "github.com/nikkolasg/hexjson" "github.com/prometheus/client_golang/prometheus/promhttp" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "github.com/drand/drand/chain" "github.com/drand/drand/client" @@ -82,18 +83,52 @@ func New(ctx context.Context, version string) (*DrandHandler, error) { beacons: make(map[string]*BeaconHandler), } - mux := chi.NewMux() + instrument := func(h http.HandlerFunc, name string) http.HandlerFunc { + return withCommonHeaders( + version, + otelhttp.NewHandler(h, name).ServeHTTP, + ) + } - mux.HandleFunc("/{"+chainHashParamKey+"}/public/latest", withCommonHeaders(version, handler.LatestRand)) - mux.HandleFunc("/{"+chainHashParamKey+"}/public/{"+roundParamKey+"}", withCommonHeaders(version, handler.PublicRand)) - mux.HandleFunc("/{"+chainHashParamKey+"}/info", withCommonHeaders(version, handler.ChainInfo)) - mux.HandleFunc("/{"+chainHashParamKey+"}/health", withCommonHeaders(version, handler.Health)) + mux := chi.NewMux() - mux.HandleFunc("/public/latest", withCommonHeaders(version, handler.LatestRand)) - mux.HandleFunc("/public/{"+roundParamKey+"}", withCommonHeaders(version, handler.PublicRand)) - mux.HandleFunc("/info", withCommonHeaders(version, handler.ChainInfo)) - mux.HandleFunc("/health", withCommonHeaders(version, handler.Health)) - mux.HandleFunc("/chains", withCommonHeaders(version, handler.ChainHashes)) + mux.HandleFunc( + "/{"+chainHashParamKey+"}/public/latest", + instrument(handler.LatestRand, chainHashParamKey+".LatestRand"), + ) + mux.HandleFunc( + "/{"+chainHashParamKey+"}/public/{"+roundParamKey+"}", + instrument(handler.PublicRand, chainHashParamKey+".PublicRand"), + ) + mux.HandleFunc( + "/{"+chainHashParamKey+"}/info", + instrument(handler.ChainInfo, chainHashParamKey+".ChainInfo"), + ) + mux.HandleFunc( + "/{"+chainHashParamKey+"}/health", + instrument(handler.Health, chainHashParamKey+".Health"), + ) + + mux.HandleFunc( + "/public/latest", + instrument(handler.LatestRand, "LatestRand"), + ) + mux.HandleFunc( + "/public/{"+roundParamKey+"}", + instrument(handler.PublicRand, roundParamKey+".PublicRand"), + ) + mux.HandleFunc( + "/info", + instrument(handler.ChainInfo, "ChainInfo"), + ) + mux.HandleFunc( + "/health", + instrument(handler.Health, "Health"), + ) + mux.HandleFunc( + "/chains", + instrument(handler.ChainHashes, "ChainHashes"), + ) handler.httpHandler = promhttp.InstrumentHandlerCounter( metrics.HTTPCallCounter, diff --git a/http/server_test.go b/http/server_test.go index fd6937bae..cfee4f7b5 100644 --- a/http/server_test.go +++ b/http/server_test.go @@ -55,6 +55,8 @@ func TestHTTPRelay(t *testing.T) { ctx, cancel := context.WithCancel(ctx) defer cancel() + test.Tracer(t, ctx) + clk := clock.NewFakeClockAt(time.Now()) c, _ := withClient(t, clk) @@ -166,6 +168,8 @@ func TestHTTPWaiting(t *testing.T) { ctx, cancel := context.WithCancel(ctx) defer cancel() + test.Tracer(t, ctx) + clk := clock.NewFakeClockAt(time.Now()) c, push := withClient(t, clk) @@ -243,6 +247,8 @@ func TestHTTPWatchFuture(t *testing.T) { clk := clock.NewFakeClockAt(time.Now()) c, _ := withClient(t, clk) + test.Tracer(t, ctx) + handler, err := New(ctx, "") if err != nil { t.Fatal(err) @@ -283,6 +289,9 @@ func TestHTTPHealth(t *testing.T) { ctx := log.ToContext(context.Background(), lg) ctx, cancel := context.WithCancel(ctx) defer cancel() + + test.Tracer(t, ctx) + clk := clock.NewFakeClockAt(time.Now()) c, push := withClient(t, clk) diff --git a/key/store.go b/key/store.go index f4fef9fb1..75aa37b20 100644 --- a/key/store.go +++ b/key/store.go @@ -167,7 +167,7 @@ func (f *fileStore) LoadShare(sch *crypto.Scheme) (*Share, error) { return s, Load(f.shareFile, s) } -func (f *fileStore) Reset(...ResetOption) error { +func (f *fileStore) Reset(_ ...ResetOption) error { if err := Delete(f.distKeyFile); err != nil { return fmt.Errorf("drand: err deleting dist. key file: %w", err) } diff --git a/metrics/metrics.go b/metrics/metrics.go index 5e4977ce7..288211f48 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -1,6 +1,7 @@ package metrics import ( + "context" "errors" "fmt" "net" @@ -352,7 +353,7 @@ func RegisterClientMetrics(r prometheus.Registerer) error { } // GroupHandlers abstracts a helper for relaying http requests to a group peer -type Handler func(addr string) (http.Handler, error) +type Handler func(ctx context.Context, addr string) (http.Handler, error) // Start starts a prometheus metrics server with debug endpoints. // @@ -439,7 +440,7 @@ func newLazyPeerHandler(logger log.Logger, metricsHandlers []Handler) *lazyPeerH // // If the peer is not found, it will return a nil handler and a nil error. // If there is any other error it will return false and the given error. -func (l *lazyPeerHandler) handlerForPeer(addr string) (http.Handler, error) { +func (l *lazyPeerHandler) handlerForPeer(ctx context.Context, addr string) (http.Handler, error) { h, found := l.handlerCache.Load(addr) if found && h != nil { return h.(http.Handler), nil @@ -448,7 +449,7 @@ func (l *lazyPeerHandler) handlerForPeer(addr string) (http.Handler, error) { var err error for _, handlerFunc := range l.metricsHandlers { - h, err = handlerFunc(addr) + h, err = handlerFunc(ctx, addr) if err != nil { if errors.Is(err, common.ErrNotPartOfGroup) { continue @@ -476,7 +477,7 @@ func (l *lazyPeerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { addr = addr[:index] } - handler, err := l.handlerForPeer(addr) + handler, err := l.handlerForPeer(r.Context(), addr) if err != nil { if errors.Is(err, common.ErrPeerNotFound) { diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index 93634d2a0..87ba51dce 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -1,6 +1,7 @@ package metrics import ( + "context" "errors" "fmt" "net/http" @@ -21,7 +22,7 @@ func TestMetricReshare(t *testing.T) { calls["nogroup.com"] = 0 calls["undefined"] = 0 - hdl := func(addr string) (http.Handler, error) { + hdl := func(ctx context.Context, addr string) (http.Handler, error) { switch addr { case "test.com": calls["test.com"]++ @@ -106,12 +107,13 @@ func TestBuildTimestamp(t *testing.T) { } func TestCreatingMetricHandlerWithoutHandlerDoesntPanic(t *testing.T) { - funcReturningNil := func(_ string) (http.Handler, error) { + ctx := context.Background() + funcReturningNil := func(_ context.Context, _ string) (http.Handler, error) { return nil, nil } h := newLazyPeerHandler(testlogger.New(t), []Handler{funcReturningNil}) - _, err := h.handlerForPeer("127.0.0.1") + _, err := h.handlerForPeer(ctx, "127.0.0.1") require.Error(t, err) } diff --git a/metrics/tracer.go b/metrics/tracer.go new file mode 100644 index 000000000..125660901 --- /dev/null +++ b/metrics/tracer.go @@ -0,0 +1,132 @@ +package metrics + +import ( + "context" + "fmt" + "sync" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.18.0" + oteltrace "go.opentelemetry.io/otel/trace" +) + +var myAppName string +var appNameOnce = &sync.Once{} + +// InitTracer returns the configured OTEL tracer. +// +//nolint:gocritic +func InitTracer(appName, endpoint string, probability float64) (oteltrace.Tracer, func(context.Context)) { + appNameOnce.Do(func() { + myAppName = appName + }) + + switch true { + case probability < 0: + probability = 0 + case probability > 1: + probability = 1 + } + + if endpoint == "" || + probability == 0 { + return noopTracer(appName) + } + + // Bootstrap tracer + traceProvider, err := startTracing( + appName, + endpoint, + probability, + ) + if err != nil { + return nil, nil + } + + tracerShutdown := func(ctx context.Context) { + err := traceProvider.Shutdown(ctx) + if err != nil { + //nolint:forbidigo + fmt.Printf("failed to shutdown tracer: %v\n", err) + } + } + + tracer := traceProvider.Tracer(appName) + + return tracer, tracerShutdown +} + +// NewSpan is a wrapper for metrics.NewSpan(ctx, spanName, opts). +// Don't forget to defer span.End and use the newly provided context. +func NewSpan(ctx context.Context, spanName string, opts ...oteltrace.SpanStartOption) (context.Context, oteltrace.Span) { + return otel.Tracer(myAppName).Start(ctx, spanName, opts...) +} + +// NewSpanFromSpanContext is like NewSpan but uses a custom span context to work +// +//nolint:lll // The name of the parameters are long. +func NewSpanFromSpanContext(ctx context.Context, spCtx oteltrace.SpanContext, spanName string, opts ...oteltrace.SpanStartOption) (context.Context, oteltrace.Span) { + return otel.Tracer(myAppName).Start(oteltrace.ContextWithSpanContext(ctx, spCtx), spanName, opts...) +} + +//nolint:gocritic +func noopTracer(appName string) (oteltrace.Tracer, func(context.Context)) { + traceProvider := oteltrace.NewNoopTracerProvider() + otel.SetTracerProvider(traceProvider) + + return traceProvider.Tracer(appName), func(context.Context) {} +} + +// startTracing configure OpenTelemetry. +func startTracing(serviceName, reporterURI string, probability float64) (*trace.TracerProvider, error) { + ctx := context.Background() + exporter, err := otlptrace.New( + ctx, + otlptracegrpc.NewClient( + otlptracegrpc.WithInsecure(), // This should be configurable + otlptracegrpc.WithEndpoint(reporterURI), + ), + ) + if err != nil { + return nil, fmt.Errorf("creating new exporter: %w", err) + } + + resources, err := resource.New( + ctx, + // resource.WithFromEnv(), // pull attributes from OTEL_RESOURCE_ATTRIBUTES and OTEL_SERVICE_NAME environment variables + // resource.WithProcess(), // This option configures a set of Detectors that discover process information + // resource.WithOS(), // This option configures a set of Detectors that discover OS information + // resource.WithContainer(), // This option configures a set of Detectors that discover container information + // resource.WithHost(), // This option configures a set of Detectors that discover host information + resource.WithAttributes( + semconv.ServiceNameKey.String(serviceName), + attribute.String("library.language", "go"), + ), + ) + + if err != nil { + return nil, fmt.Errorf("creating new exporter: %w", err) + } + + traceProvider := trace.NewTracerProvider( + trace.WithSampler(trace.TraceIDRatioBased(probability)), + trace.WithBatcher(exporter, + trace.WithMaxExportBatchSize(trace.DefaultMaxExportBatchSize), + trace.WithBatchTimeout(trace.DefaultScheduleDelay*time.Millisecond), + ), + + trace.WithResource(resources), + ) + + // We must set this provider as the global provider. + otel.SetTracerProvider(traceProvider) + otel.SetTextMapPropagator(propagation.TraceContext{}) + return traceProvider, nil +} diff --git a/net/client.go b/net/client.go index dfd186333..f0be1c19c 100644 --- a/net/client.go +++ b/net/client.go @@ -50,7 +50,7 @@ type PublicClient interface { // HTTPClient is an optional extension to the protocol client relaying of HTTP over the GRPC connection. // it is currently used for relaying metrics between group members. type HTTPClient interface { - HandleHTTP(p Peer) (http.Handler, error) + HandleHTTP(ctx context.Context, p Peer) (http.Handler, error) } // listenAddrFor parses the address specified into a dialable / listenable address diff --git a/net/client_grpc.go b/net/client_grpc.go index 12c4d128c..f431646ba 100644 --- a/net/client_grpc.go +++ b/net/client_grpc.go @@ -13,6 +13,7 @@ import ( "github.com/weaveworks/common/httpgrpc" httpgrpcserver "github.com/weaveworks/common/httpgrpc/server" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "golang.org/x/net/proxy" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -95,7 +96,7 @@ func (g *grpcClient) getTimeoutContext(ctx context.Context) (context.Context, co func (g *grpcClient) GetIdentity(ctx context.Context, p Peer, in *drand.IdentityRequest, opts ...CallOption) (*drand.IdentityResponse, error) { var resp *drand.IdentityResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -107,7 +108,7 @@ func (g *grpcClient) GetIdentity(ctx context.Context, p Peer, } func (g *grpcClient) PublicRand(ctx context.Context, p Peer, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -126,7 +127,7 @@ func (g *grpcClient) PublicRandStream( in *drand.PublicRandRequest, opts ...CallOption) (chan *drand.PublicRandResponse, error) { var outCh = make(chan *drand.PublicRandResponse, grpcClientRandStreamBacklog) - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -163,7 +164,7 @@ func (g *grpcClient) PublicRandStream( func (g *grpcClient) ChainInfo(ctx context.Context, p Peer, in *drand.ChainInfoRequest) (*drand.ChainInfoPacket, error) { var resp *drand.ChainInfoPacket - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -175,7 +176,10 @@ func (g *grpcClient) ChainInfo(ctx context.Context, p Peer, in *drand.ChainInfoR } func (g *grpcClient) PartialBeacon(ctx context.Context, p Peer, in *drand.PartialBeaconPacket, opts ...CallOption) error { - c, err := g.conn(p) + ctx, span := metrics.NewSpan(ctx, "client.PartialBeacon") + defer span.End() + + c, err := g.conn(ctx, p) if err != nil { return err } @@ -191,7 +195,7 @@ const MaxSyncBuffer = 500 func (g *grpcClient) SyncChain(ctx context.Context, p Peer, in *drand.SyncRequest, opts ...CallOption) (chan *drand.BeaconPacket, error) { resp := make(chan *drand.BeaconPacket, MaxSyncBuffer) - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -229,7 +233,7 @@ func (g *grpcClient) SyncChain(ctx context.Context, p Peer, in *drand.SyncReques func (g *grpcClient) Home(ctx context.Context, p Peer, in *drand.HomeRequest) (*drand.HomeResponse, error) { var resp *drand.HomeResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -242,7 +246,7 @@ func (g *grpcClient) Home(ctx context.Context, p Peer, in *drand.HomeRequest) (* func (g *grpcClient) Status(ctx context.Context, p Peer, in *drand.StatusRequest, opts ...grpc.CallOption) (*drand.StatusResponse, error) { var resp *drand.StatusResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -254,7 +258,7 @@ func (g *grpcClient) Status(ctx context.Context, p Peer, in *drand.StatusRequest } // conn retrieve an already existing conn to the given peer or create a new one -func (g *grpcClient) conn(p Peer) (*grpc.ClientConn, error) { +func (g *grpcClient) conn(ctx context.Context, p Peer) (*grpc.ClientConn, error) { g.Lock() defer g.Unlock() var err error @@ -269,7 +273,15 @@ func (g *grpcClient) conn(p Peer) (*grpc.ClientConn, error) { if !ok { g.log.Debugw("", "grpc client", "initiating", "to", p.Address(), "tls", p.IsTLS()) if !p.IsTLS() { - c, err = grpc.Dial(p.Address(), append(g.opts, grpc.WithTransportCredentials(insecure.NewCredentials()))...) + var opts []grpc.DialOption + opts = append(opts, g.opts...) + opts = append(opts, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), + ) + + c, err = grpc.DialContext(ctx, p.Address(), opts...) if err != nil { metrics.GroupDialFailures.WithLabelValues(p.Address()).Inc() } @@ -284,7 +296,11 @@ func (g *grpcClient) conn(p Peer) (*grpc.ClientConn, error) { config := &tls.Config{MinVersion: tls.VersionTLS12} opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(config))) } - c, err = grpc.Dial(p.Address(), opts...) + opts = append(opts, + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), + ) + c, err = grpc.DialContext(ctx, p.Address(), opts...) if err != nil { metrics.GroupDialFailures.WithLabelValues(p.Address()).Inc() } @@ -330,8 +346,8 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func (g *grpcClient) HandleHTTP(p Peer) (http.Handler, error) { - conn, err := g.conn(p) +func (g *grpcClient) HandleHTTP(ctx context.Context, p Peer) (http.Handler, error) { + conn, err := g.conn(ctx, p) if err != nil { return nil, err } diff --git a/net/listener.go b/net/listener.go index 98fdf65dc..c95156653 100644 --- a/net/listener.go +++ b/net/listener.go @@ -8,10 +8,12 @@ import ( "sync" "time" - grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" - http_grpc "github.com/weaveworks/common/httpgrpc" - http_grpc_server "github.com/weaveworks/common/httpgrpc/server" + grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + "github.com/weaveworks/common/httpgrpc" + httpgrpcserver "github.com/weaveworks/common/httpgrpc/server" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -24,7 +26,7 @@ var isGrpcPrometheusMetricsRegisted = false var state sync.Mutex func registerGRPCMetrics(l log.Logger) error { - if err := metrics.PrivateMetrics.Register(grpc_prometheus.DefaultServerMetrics); err != nil { + if err := metrics.PrivateMetrics.Register(grpcprometheus.DefaultServerMetrics); err != nil { l.Warnw("", "grpc Listener", "failed metrics registration", "err", err) return err } @@ -56,8 +58,22 @@ func NewGRPCListenerForPrivate( } opts = append(opts, - grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(grpc_prometheus.StreamServerInterceptor, s.NodeVersionStreamValidator)), - grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(grpc_prometheus.UnaryServerInterceptor, s.NodeVersionValidator)), + grpc.StreamInterceptor( + grpcmiddleware.ChainStreamServer( + otelgrpc.StreamServerInterceptor(), + grpcprometheus.StreamServerInterceptor, + s.NodeVersionStreamValidator, + grpcrecovery.StreamServerInterceptor(), // TODO (dlsniper): This turns panics into grpc errors. Do we want that? + ), + ), + grpc.UnaryInterceptor( + grpcmiddleware.ChainUnaryServer( + otelgrpc.UnaryServerInterceptor(), + grpcprometheus.UnaryServerInterceptor, + s.NodeVersionValidator, + grpcrecovery.UnaryServerInterceptor(), // TODO (dlsniper): This turns panics into grpc errors. Do we want that? + ), + ), ) grpcServer := grpc.NewServer(opts...) @@ -87,8 +103,8 @@ func NewGRPCListenerForPrivate( g = gr } - http_grpc.RegisterHTTPServer(grpcServer, http_grpc_server.NewServer(metrics.GroupHandlerWithLogger(l))) - grpc_prometheus.Register(grpcServer) + httpgrpc.RegisterHTTPServer(grpcServer, httpgrpcserver.NewServer(metrics.GroupHandlerWithLogger(l))) + grpcprometheus.Register(grpcServer) state.Lock() defer state.Unlock() diff --git a/net/peer.go b/net/peer.go index 04f7c14ce..c35057d96 100644 --- a/net/peer.go +++ b/net/peer.go @@ -50,8 +50,8 @@ func CreatePeer(addr string, tls bool) Peer { // } // // ``` -func RemoteAddress(c context.Context) string { - p, ok := peer.FromContext(c) +func RemoteAddress(ctx context.Context) string { + p, ok := peer.FromContext(ctx) str := "" if ok { str = p.Addr.String() @@ -81,7 +81,7 @@ func RemoteAddress(c context.Context) string { return str } - md, ok := metadata.FromIncomingContext(c) + md, ok := metadata.FromIncomingContext(ctx) if !ok { return str } diff --git a/test/docker-compose.yaml b/test/docker-compose.yaml deleted file mode 100644 index 9c037557e..000000000 --- a/test/docker-compose.yaml +++ /dev/null @@ -1,10 +0,0 @@ -version: "3.8" -services: - postgres: - image: postgres:15.1-alpine3.16 - environment: - - POSTGRES_USER=drand - - POSTGRES_PASSWORD=drand - - POSTGRES_DB=drand - ports: - - 35432:5432 diff --git a/test/key_store.go b/test/key_store.go index f4291b54f..5465a250c 100644 --- a/test/key_store.go +++ b/test/key_store.go @@ -51,7 +51,7 @@ func (k *KeyStore) LoadDistPublic() (*key.DistPublic, error) { return k.dist, nil } -func (k *KeyStore) Reset(...key.ResetOption) error { +func (k *KeyStore) Reset(_ ...key.ResetOption) error { k.group = nil k.dist = nil k.share = nil diff --git a/test/metrics.go b/test/metrics.go new file mode 100644 index 000000000..b288a2570 --- /dev/null +++ b/test/metrics.go @@ -0,0 +1,34 @@ +package test + +import ( + "context" + "fmt" + "os" + "testing" + + oteltrace "go.opentelemetry.io/otel/trace" + + "github.com/drand/drand/metrics" +) + +// Tracer ... +func Tracer(t *testing.T, ctx context.Context) oteltrace.Tracer { + endpoint := os.Getenv("DRAND_TRACES") + tracer, tracerShutdown := metrics.InitTracer(t.Name(), endpoint, 1) + t.Cleanup(func() { + tracerShutdown(ctx) + }) + + return tracer +} + +// TracerWithName adds the `_$name` suffix to the tracer name +func TracerWithName(t *testing.T, ctx context.Context, name string) oteltrace.Tracer { + endpoint := os.Getenv("DRAND_TRACES") + tracer, tracerShutdown := metrics.InitTracer(fmt.Sprintf("%s_%s", t.Name(), name), endpoint, 1) + t.Cleanup(func() { + tracerShutdown(ctx) + }) + + return tracer +} From ce821c2d72b648c712174a3910bbd92aa9d35c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Fri, 24 Mar 2023 17:51:21 +0200 Subject: [PATCH 2/9] Fixes after rebase --- chain/beacon/node.go | 2 ++ chain/beacon/store.go | 8 +++--- cmd/relay/main.go | 1 - core/drand_beacon.go | 52 +++++++++++++++++++++--------------- core/drand_beacon_control.go | 1 + core/drand_daemon.go | 8 +++--- core/drand_daemon_control.go | 3 ++- core/drand_test.go | 12 ++++----- core/util_test.go | 8 +++--- demo/demo_test.go | 3 ++- demo/node/proposal_file.go | 3 ++- dkg/actions_active.go | 5 ++-- dkg/actions_passive.go | 4 +-- dkg/broadcast.go | 12 ++++----- dkg/broadcast_test.go | 5 ++++ dkg/execution.go | 4 ++- go.mod | 1 - go.sum | 1 + http/server_test.go | 4 ++- net/client_grpc_dkg.go | 27 ++++++++++--------- 20 files changed, 92 insertions(+), 72 deletions(-) diff --git a/chain/beacon/node.go b/chain/beacon/node.go index 73377b003..d6057d839 100644 --- a/chain/beacon/node.go +++ b/chain/beacon/node.go @@ -367,6 +367,8 @@ func (h *Handler) Reset(ctx context.Context) { } // run will wait until it is supposed to start +// +//nolint:funlen // This is a long function func (h *Handler) run(startTime int64) { chanTick := h.ticker.ChannelAt(startTime) diff --git a/chain/beacon/store.go b/chain/beacon/store.go index 5b452bacc..bcf17e998 100644 --- a/chain/beacon/store.go +++ b/chain/beacon/store.go @@ -85,10 +85,8 @@ func (a *appendStore) Put(ctx context.Context, b *chain.Beacon) error { return nil } -// SchemeStore is a store that run different checks depending on what scheme is being used. -// -//nolint:gocritic -type SchemeStore struct { +// schemeStore is a store that run different checks depending on what scheme is being used. +type schemeStore struct { chain.Store sch *crypto.Scheme last *chain.Beacon @@ -109,7 +107,7 @@ func NewSchemeStore(ctx context.Context, s chain.Store, sch *crypto.Scheme) (cha }, nil } -func (a *SchemeStore) Put(ctx context.Context, b *chain.Beacon) error { +func (a *schemeStore) Put(ctx context.Context, b *chain.Beacon) error { ctx, span := metrics.NewSpan(ctx, "schemeStore.Put") defer span.End() diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 80e96cf14..1b8f2b396 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -1,7 +1,6 @@ package main import ( - "context" "encoding/hex" "fmt" "net" diff --git a/core/drand_beacon.go b/core/drand_beacon.go index f30687c3d..920732616 100644 --- a/core/drand_beacon.go +++ b/core/drand_beacon.go @@ -8,6 +8,8 @@ import ( "sync" "time" + oteltrace "go.opentelemetry.io/otel/trace" + "github.com/drand/drand/protobuf/drand" "github.com/drand/drand/dkg" @@ -112,7 +114,7 @@ var ErrDKGNotStarted = errors.New("DKG not started") // pre-existing distributed share. // Returns 'true' if this BeaconProcess is a fresh run, returns 'false' otherwise func (bp *BeaconProcess) Load(ctx context.Context) error { - ctx, span := metrics.NewSpan(ctx, "bp.Load") + _, span := metrics.NewSpan(ctx, "bp.Load") defer span.End() var err error @@ -121,6 +123,7 @@ func (bp *BeaconProcess) Load(ctx context.Context) error { bp.group, err = bp.store.LoadGroup() if err != nil || bp.group == nil { metrics.DKGStateChange(metrics.DKGNotStarted, beaconID, false) + span.RecordError(err) return ErrDKGNotStarted } @@ -130,6 +133,7 @@ func (bp *BeaconProcess) Load(ctx context.Context) error { "priv", bp.priv.Public.Scheme.Name, "group", bp.group.Scheme.Name) // we need to reload the keypair with the correct scheme if bp.priv, err = bp.store.LoadKeyPair(bp.group.Scheme); err != nil { + span.RecordError(err) return err } } @@ -142,12 +146,15 @@ func (bp *BeaconProcess) Load(ctx context.Context) error { bp.share, err = bp.store.LoadShare(bp.group.Scheme) if err != nil { + span.RecordError(err) return err } thisBeacon := bp.group.Find(bp.priv.Public) if thisBeacon == nil { - return fmt.Errorf("could not restore beacon info for the given identity - this can happen if you updated the group file manually") + err := fmt.Errorf("could not restore beacon info for the given identity - this can happen if you updated the group file manually") + span.RecordError(err) + return err } bp.state.Lock() bp.index = int(thisBeacon.Index) @@ -189,9 +196,10 @@ func (bp *BeaconProcess) StartBeacon(ctx context.Context, catchup bool) error { return nil } -func (bp *BeaconProcess) StartListeningForDKGUpdates() { +func (bp *BeaconProcess) StartListeningForDKGUpdates(sctx oteltrace.SpanContext) { + ctx := oteltrace.ContextWithSpanContext(context.Background(), sctx) for dkgOutput := range bp.completedDKGs { - if err := bp.onDKGCompleted(&dkgOutput); err != nil { + if err := bp.onDKGCompleted(ctx, &dkgOutput); err != nil { bp.log.Errorw("Error performing DKG key transition", "err", err) } } @@ -199,7 +207,7 @@ func (bp *BeaconProcess) StartListeningForDKGUpdates() { // onDKGCompleted transitions between an "old" group and a new group. This method is called // *after* a DKG has completed. -func (bp *BeaconProcess) onDKGCompleted(dkgOutput *dkg.SharingOutput) error { +func (bp *BeaconProcess) onDKGCompleted(ctx context.Context, dkgOutput *dkg.SharingOutput) error { if dkgOutput.BeaconID != bp.beaconID { bp.log.Infow(fmt.Sprintf("BeaconProcess for beaconID %s ignoring DKG for beaconID %s", bp.beaconID, dkgOutput.BeaconID)) return nil @@ -227,18 +235,18 @@ func (bp *BeaconProcess) onDKGCompleted(dkgOutput *dkg.SharingOutput) error { if weWereInLastEpoch { if weAreInNextEpoch { - return bp.transitionToNext(dkgOutput) + return bp.transitionToNext(ctx, dkgOutput) } - return bp.leaveNetwork() + return bp.leaveNetwork(ctx) } if weAreInNextEpoch { - return bp.joinNetwork(dkgOutput) + return bp.joinNetwork(ctx, dkgOutput) } return errors.New("failed to join the network during the DKG but somehow got to transition") } -func (bp *BeaconProcess) transitionToNext(dkgOutput *dkg.SharingOutput) error { +func (bp *BeaconProcess) transitionToNext(ctx context.Context, dkgOutput *dkg.SharingOutput) error { newGroup := dkgOutput.New.FinalGroup newShare := dkgOutput.New.KeyShare @@ -246,23 +254,23 @@ func (bp *BeaconProcess) transitionToNext(dkgOutput *dkg.SharingOutput) error { if err != nil { return err } - err = bp.storeDKGOutput(newGroup, newShare) + err = bp.storeDKGOutput(ctx, newGroup, newShare) if err != nil { return err } // somehow the beacon process isn't set here sometimes o.O if bp.beacon == nil { - b, err := bp.newBeacon(context.Background()) + b, err := bp.newBeacon(ctx) if err != nil { return err } bp.beacon = b } - bp.beacon.TransitionNewGroup(newShare, newGroup) + bp.beacon.TransitionNewGroup(ctx, newShare, newGroup) // keep the old beacon running until the `TransitionTime` - if err := bp.beacon.Transition(dkgOutput.Old.FinalGroup); err != nil { + if err := bp.beacon.Transition(ctx, dkgOutput.Old.FinalGroup); err != nil { bp.log.Errorw("", "sync_before", err) } else { bp.log.Infow("", "transition_new", "done") @@ -271,7 +279,7 @@ func (bp *BeaconProcess) transitionToNext(dkgOutput *dkg.SharingOutput) error { return err } -func (bp *BeaconProcess) storeDKGOutput(group *key.Group, share *key.Share) error { +func (bp *BeaconProcess) storeDKGOutput(ctx context.Context, group *key.Group, share *key.Share) error { bp.state.Lock() defer bp.state.Unlock() bp.group = group @@ -288,14 +296,14 @@ func (bp *BeaconProcess) storeDKGOutput(group *key.Group, share *key.Share) erro return err } - bp.opts.dkgCallback(share, group) + bp.opts.dkgCallback(ctx, share, group) return nil } -func (bp *BeaconProcess) leaveNetwork() error { +func (bp *BeaconProcess) leaveNetwork(ctx context.Context) error { timeToStop := bp.group.TransitionTime - 1 - err := bp.beacon.StopAt(timeToStop) + err := bp.beacon.StopAt(ctx, timeToStop) if err != nil { bp.log.Errorw("", "leaving_group", err) } else { @@ -305,7 +313,7 @@ func (bp *BeaconProcess) leaveNetwork() error { return err } -func (bp *BeaconProcess) joinNetwork(dkgOutput *dkg.SharingOutput) error { +func (bp *BeaconProcess) joinNetwork(ctx context.Context, dkgOutput *dkg.SharingOutput) error { newGroup := dkgOutput.New.FinalGroup newShare := dkgOutput.New.KeyShare @@ -317,7 +325,7 @@ func (bp *BeaconProcess) joinNetwork(dkgOutput *dkg.SharingOutput) error { } } - err := bp.storeDKGOutput(newGroup, newShare) + err := bp.storeDKGOutput(ctx, newGroup, newShare) if err != nil { return err } @@ -328,11 +336,11 @@ func (bp *BeaconProcess) joinNetwork(dkgOutput *dkg.SharingOutput) error { return err } - bp.beacon.TransitionNewGroup(newShare, newGroup) + bp.beacon.TransitionNewGroup(ctx, newShare, newGroup) - syncError := b.Start() + syncError := b.Start(ctx) if syncError != nil { - b.Catchup() + b.Catchup(ctx) } return nil diff --git a/core/drand_beacon_control.go b/core/drand_beacon_control.go index 659e20782..9125181d5 100644 --- a/core/drand_beacon_control.go +++ b/core/drand_beacon_control.go @@ -8,6 +8,7 @@ import ( "time" "github.com/drand/drand/key" + "github.com/drand/drand/metrics" clock "github.com/jonboulle/clockwork" "go.opentelemetry.io/otel/attribute" diff --git a/core/drand_daemon.go b/core/drand_daemon.go index e1096bdf3..cf35e9639 100644 --- a/core/drand_daemon.go +++ b/core/drand_daemon.go @@ -8,9 +8,9 @@ import ( "go.opentelemetry.io/otel/attribute" - "github.com/drand/drand/dkg" "github.com/drand/drand/chain" "github.com/drand/drand/common" + "github.com/drand/drand/dkg" dhttp "github.com/drand/drand/http" "github.com/drand/drand/key" "github.com/drand/drand/log" @@ -134,7 +134,7 @@ func (dd *DrandDaemon) init(ctx context.Context) error { // Gateway constructors (specifically, the generated gateway stubs that require it) // do not actually use it, so we are passing a background context to be safe. lg := dd.log.With("server", "http") - ctx := log.ToContext(context.Background(), lg) + ctx = log.ToContext(ctx, lg) var err error dd.log.Infow("", "network", "init", "insecure", c.insecure) @@ -208,7 +208,7 @@ func (dd *DrandDaemon) InstantiateBeaconProcess(ctx context.Context, beaconID st span.RecordError(err) return nil, err } - go bp.StartListeningForDKGUpdates() + go bp.StartListeningForDKGUpdates(span.SpanContext()) dd.state.Lock() dd.beaconProcesses[beaconID] = bp @@ -383,7 +383,7 @@ func (dd *DrandDaemon) LoadBeaconFromStore(ctx context.Context, beaconID string, return bp, nil } - if err := bp.Load(); err != nil { + if err := bp.Load(ctx); err != nil { return nil, err } dd.log.Infow(fmt.Sprintf("beacon id [%s]: will start running randomness beacon.", beaconID)) diff --git a/core/drand_daemon_control.go b/core/drand_daemon_control.go index 8d34c7859..265cfa804 100644 --- a/core/drand_daemon_control.go +++ b/core/drand_daemon_control.go @@ -8,13 +8,14 @@ import ( "github.com/drand/drand/crypto" "github.com/drand/drand/key" + "github.com/drand/drand/metrics" "github.com/drand/drand/protobuf/common" "github.com/drand/drand/protobuf/drand" ) // PingPong simply responds with an empty packet, proving that this drand node // is up and alive. -func (dd *DrandDaemon) PingPong(ctx context.Context, in *drand.Ping) (*drand.Pong, error) { +func (dd *DrandDaemon) PingPong(ctx context.Context, _ *drand.Ping) (*drand.Pong, error) { _, span := metrics.NewSpan(ctx, "dd.PingPong") defer span.End() diff --git a/core/drand_test.go b/core/drand_test.go index 1ff9949ef..b08a59119 100644 --- a/core/drand_test.go +++ b/core/drand_test.go @@ -388,7 +388,7 @@ func TestRunDKGReshareTimeout(t *testing.T) { for { dt.AdvanceMockClock(t, beaconPeriod) time.Sleep(sleepDuration) - dt.CheckPublicBeacon(dt.Ids(1, false)[0], false) + dt.CheckPublicBeacon(dt.NodeAddresses(1, false)[0], false) if dt.clock.Now().Unix() > resharedGroup.TransitionTime { break } @@ -541,7 +541,7 @@ func TestDrandPublicChainInfo(t *testing.T) { // Test if we can correctly fetch the rounds after a DKG using the PublicRand RPC call // -//nolint:funlen // this is a test +//nolint:funlen // This is a longer test function func TestDrandPublicRand(t *testing.T) { if os.Getenv("CI") == "true" { t.Skip("test is flacky in CI") @@ -1177,7 +1177,7 @@ func TestModifyingGroupFileManuallyDoesNotSegfault(t *testing.T) { err = os.WriteFile(groupPath, []byte(strings.ReplaceAll(string(groupFile), "true", "false")), 0o740) require.NoError(t, err) - err = node.daemon.init() + err = node.daemon.init(ctx) require.NoError(t, err) // try and reload the beacon from the store // the updated TLS status will fail verification @@ -1255,7 +1255,7 @@ func (d *DrandTestScenario) AddNodesWithOptions(t *testing.T, n int, beaconID st type brokenBroadcast struct { } -func (b brokenBroadcast) PushDeals(bundle *dkg.DealBundle) { +func (b brokenBroadcast) PushDeals(*dkg.DealBundle) { // no op } @@ -1265,7 +1265,7 @@ func (b brokenBroadcast) IncomingDeal() <-chan dkg.DealBundle { return c } -func (b brokenBroadcast) PushResponses(bundle *dkg.ResponseBundle) { +func (b brokenBroadcast) PushResponses(*dkg.ResponseBundle) { // no op } @@ -1275,7 +1275,7 @@ func (b brokenBroadcast) IncomingResponse() <-chan dkg.ResponseBundle { return c } -func (b brokenBroadcast) PushJustifications(bundle *dkg.JustificationBundle) { +func (b brokenBroadcast) PushJustifications(*dkg.JustificationBundle) { // no op } diff --git a/core/util_test.go b/core/util_test.go index bf78914f4..a2648c4a7 100644 --- a/core/util_test.go +++ b/core/util_test.go @@ -21,7 +21,6 @@ import ( "github.com/drand/drand/common" "github.com/drand/drand/crypto" "github.com/drand/drand/key" - "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/protobuf/drand" "github.com/drand/drand/test" @@ -230,10 +229,9 @@ func NewDrandTestScenario(t *testing.T, n, thr int, period time.Duration, beacon return dt } -// Ids returns the list of the first n ids given the newGroup parameter (either +// NodeAddresses returns the list of the first n ids given the newGroup parameter (either // in the original group or the reshared one) -// Deprecated: Rename this to addresses to align naming -func (d *DrandTestScenario) Ids(n int, newGroup bool) []string { +func (d *DrandTestScenario) NodeAddresses(n int, newGroup bool) []string { nodes := d.nodes if newGroup { nodes = d.resharedNodes @@ -410,7 +408,7 @@ func (d *DrandTestScenario) SetupNewNodes(t *testing.T, countOfAdditionalNodes i node, err := newNode(d.clock.Now(), newCertPaths[i], newDaemons[i], inst) if err != nil { fmt.Println("could not construct mock node") - t.Fail() + t.Fatal("could not construct mock node") } d.newNodes[i] = node node.daemon.opts.logger.Named(fmt.Sprintf("node %d", len(d.nodes)+1)) diff --git a/demo/demo_test.go b/demo/demo_test.go index fc715fb86..f8ec825c0 100644 --- a/demo/demo_test.go +++ b/demo/demo_test.go @@ -4,10 +4,11 @@ package main_test import ( "context" - "github.com/stretchr/testify/require" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/drand/drand/crypto" "github.com/drand/drand/demo/cfg" "github.com/drand/drand/demo/lib" diff --git a/demo/node/proposal_file.go b/demo/node/proposal_file.go index 9a6fb5cd2..416e0c171 100644 --- a/demo/node/proposal_file.go +++ b/demo/node/proposal_file.go @@ -3,10 +3,11 @@ package node import ( "bytes" "encoding/hex" + "os" + "github.com/BurntSushi/toml" cli "github.com/drand/drand/cmd/drand-cli" "github.com/drand/drand/protobuf/drand" - "os" ) type ProposalFile struct { diff --git a/dkg/actions_active.go b/dkg/actions_active.go index a4bc8d752..61a419f19 100644 --- a/dkg/actions_active.go +++ b/dkg/actions_active.go @@ -9,9 +9,10 @@ import ( "github.com/drand/drand/net" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/drand/drand/protobuf/drand" "github.com/drand/drand/util" - "google.golang.org/protobuf/types/known/timestamppb" ) // actions_active contains all the DKG actions that require user interaction: creating a network, @@ -260,7 +261,7 @@ func (d *DKGProcess) StartExecute(ctx context.Context, options *drand.ExecutionO } // set up the DKG broadcaster for first so we're ready to broadcast DKG messages - dkgConfig, err := d.setupDKG(beaconID) + dkgConfig, err := d.setupDKG(ctx, beaconID) if err != nil { return nil, err } diff --git a/dkg/actions_passive.go b/dkg/actions_passive.go index bfd63ad26..255c1c778 100644 --- a/dkg/actions_passive.go +++ b/dkg/actions_passive.go @@ -45,7 +45,7 @@ func (d *DKGProcess) Abort(_ context.Context, abort *drand.AbortDKG) (*drand.Emp return responseOrError(err) } -func (d *DKGProcess) Execute(_ context.Context, kickoff *drand.StartExecution) (*drand.EmptyResponse, error) { +func (d *DKGProcess) Execute(ctx context.Context, kickoff *drand.StartExecution) (*drand.EmptyResponse, error) { beaconID := kickoff.Metadata.BeaconID err := d.executeAction("DKG execution", beaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -58,7 +58,7 @@ func (d *DKGProcess) Execute(_ context.Context, kickoff *drand.StartExecution) ( } d.log.Infow("DKG execution started successfully", "beaconID", beaconID) - dkgConfig, err := d.setupDKG(beaconID) + dkgConfig, err := d.setupDKG(ctx, beaconID) if err != nil { return nil, err } diff --git a/dkg/broadcast.go b/dkg/broadcast.go index 7158a8ff3..9762bf355 100644 --- a/dkg/broadcast.go +++ b/dkg/broadcast.go @@ -10,16 +10,16 @@ import ( oteltrace "go.opentelemetry.io/otel/trace" - "github.com/drand/drand/protobuf/common" - pdkg "github.com/drand/drand/protobuf/crypto/dkg" - "github.com/drand/kyber" - "github.com/drand/drand/crypto" - "github.com/drand/drand/util" commonutils "github.com/drand/drand/common" + "github.com/drand/drand/crypto" "github.com/drand/drand/log" "github.com/drand/drand/metrics" "github.com/drand/drand/net" + "github.com/drand/drand/protobuf/common" + pdkg "github.com/drand/drand/protobuf/crypto/dkg" "github.com/drand/drand/protobuf/drand" + "github.com/drand/drand/util" + "github.com/drand/kyber" "github.com/drand/kyber/share/dkg" ) @@ -76,7 +76,7 @@ var _ Broadcast = (*echoBroadcast)(nil) func newEchoBroadcast( ctx context.Context, -client net.DKGClient, + client net.DKGClient, l log.Logger, version commonutils.Version, beaconID string, diff --git a/dkg/broadcast_test.go b/dkg/broadcast_test.go index e02dd24cb..62a16bcaf 100644 --- a/dkg/broadcast_test.go +++ b/dkg/broadcast_test.go @@ -1,6 +1,7 @@ package dkg import ( + "context" "testing" "github.com/drand/drand/crypto" @@ -17,9 +18,11 @@ import ( func TestNewBroadcasterWithNoParticipantsFails(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() gateway := net.PrivateGateway{} sch, _ := crypto.GetSchemeByIDWithDefault("") _, err := newEchoBroadcast( + ctx, gateway.DKGClient, l, common.GetAppVersion(), @@ -34,10 +37,12 @@ func TestNewBroadcasterWithNoParticipantsFails(t *testing.T) { func TestNewBroadcasterWithParticipantsDoesNotFail(t *testing.T) { l := testlogger.New(t) + ctx := context.Background() gateway := net.PrivateGateway{} sch, _ := crypto.GetSchemeByIDWithDefault("") _, err := newEchoBroadcast( + ctx, gateway.DKGClient, l, common.GetAppVersion(), diff --git a/dkg/execution.go b/dkg/execution.go index 6a910df4a..d686f38b6 100644 --- a/dkg/execution.go +++ b/dkg/execution.go @@ -1,6 +1,7 @@ package dkg import ( + "context" "crypto/sha256" "encoding/binary" "errors" @@ -19,7 +20,7 @@ import ( "github.com/drand/kyber/sign/schnorr" ) -func (d *DKGProcess) setupDKG(beaconID string) (*dkg.Config, error) { +func (d *DKGProcess) setupDKG(ctx context.Context, beaconID string) (*dkg.Config, error) { current, err := d.store.GetCurrent(beaconID) if err != nil { return nil, err @@ -52,6 +53,7 @@ func (d *DKGProcess) setupDKG(beaconID string) (*dkg.Config, error) { // create the network over which to send all the DKG packets board, err := newEchoBroadcast( + ctx, d.internalClient, d.log, common.GetAppVersion(), diff --git a/go.mod b/go.mod index 410018d5b..23d663b7d 100644 --- a/go.mod +++ b/go.mod @@ -164,7 +164,6 @@ require ( github.com/weaveworks/promrus v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect - go.dedis.ch/protobuf v1.0.11 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect go.opentelemetry.io/otel/metric v0.37.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect diff --git a/go.sum b/go.sum index e64f13ea1..481792f6c 100644 --- a/go.sum +++ b/go.sum @@ -1449,6 +1449,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= diff --git a/http/server_test.go b/http/server_test.go index cfee4f7b5..68d26026e 100644 --- a/http/server_test.go +++ b/http/server_test.go @@ -20,6 +20,7 @@ import ( "github.com/drand/drand/crypto" "github.com/drand/drand/log" "github.com/drand/drand/protobuf/drand" + "github.com/drand/drand/test" "github.com/drand/drand/test/mock" "github.com/drand/drand/test/testlogger" ) @@ -269,7 +270,8 @@ func TestHTTPWatchFuture(t *testing.T) { go func() { _ = server.Serve(listener) }() defer func() { _ = server.Shutdown(ctx) }() - nhttp.IsServerReady(listener.Addr().String()) + err = nhttp.IsServerReady(listener.Addr().String()) + require.NoError(t, err) // watching sets latest round, future rounds should become inaccessible. u := fmt.Sprintf("http://%s/%s/public/2000", listener.Addr().String(), info.HashString()) diff --git a/net/client_grpc_dkg.go b/net/client_grpc_dkg.go index 0ead00aa5..da8af7604 100644 --- a/net/client_grpc_dkg.go +++ b/net/client_grpc_dkg.go @@ -3,13 +3,14 @@ package net import ( "context" - "github.com/drand/drand/protobuf/drand" "google.golang.org/grpc" + + "github.com/drand/drand/protobuf/drand" ) -func (g *grpcClient) Propose(ctx context.Context, p Peer, in *drand.ProposalTerms, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) Propose(ctx context.Context, p Peer, in *drand.ProposalTerms, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -20,9 +21,9 @@ func (g *grpcClient) Propose(ctx context.Context, p Peer, in *drand.ProposalTerm return resp, err } -func (g *grpcClient) Abort(ctx context.Context, p Peer, in *drand.AbortDKG, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) Abort(ctx context.Context, p Peer, in *drand.AbortDKG, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -33,9 +34,9 @@ func (g *grpcClient) Abort(ctx context.Context, p Peer, in *drand.AbortDKG, opts return resp, err } -func (g *grpcClient) Execute(ctx context.Context, p Peer, in *drand.StartExecution, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) Execute(ctx context.Context, p Peer, in *drand.StartExecution, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -46,9 +47,9 @@ func (g *grpcClient) Execute(ctx context.Context, p Peer, in *drand.StartExecuti return resp, err } -func (g *grpcClient) Accept(ctx context.Context, p Peer, in *drand.AcceptProposal, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) Accept(ctx context.Context, p Peer, in *drand.AcceptProposal, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -59,9 +60,9 @@ func (g *grpcClient) Accept(ctx context.Context, p Peer, in *drand.AcceptProposa return resp, err } -func (g *grpcClient) Reject(ctx context.Context, p Peer, in *drand.RejectProposal, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) Reject(ctx context.Context, p Peer, in *drand.RejectProposal, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } @@ -72,9 +73,9 @@ func (g *grpcClient) Reject(ctx context.Context, p Peer, in *drand.RejectProposa return resp, err } -func (g *grpcClient) BroadcastDKG(ctx context.Context, p Peer, in *drand.DKGPacket, opts ...grpc.CallOption) (*drand.EmptyResponse, error) { +func (g *grpcClient) BroadcastDKG(ctx context.Context, p Peer, in *drand.DKGPacket, _ ...grpc.CallOption) (*drand.EmptyResponse, error) { var resp *drand.EmptyResponse - c, err := g.conn(p) + c, err := g.conn(ctx, p) if err != nil { return nil, err } From 323103cec4d13104a6e35b56eef42bfccff16332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Fri, 24 Mar 2023 19:14:01 +0200 Subject: [PATCH 3/9] Misc cleanup --- chain/beacon/node.go | 4 ++-- chain/beacon/sync_manager.go | 2 +- client/empty.go | 6 ++--- client/http/http.go | 4 ++-- client/interface.go | 1 + client/mock_test.go | 8 +++---- client/optimizing.go | 8 +++---- cmd/client/lib/cli_test.go | 2 +- cmd/drand-cli/cli.go | 2 +- cmd/drand-cli/cli_test.go | 2 +- cmd/drand-cli/proposal_file.go | 1 + cmd/relay-gossip/main.go | 4 ++-- cmd/relay/main.go | 4 ++-- core/drand_beacon_control.go | 2 +- core/drand_daemon_interceptors.go | 4 ++-- core/drand_proxy.go | 9 ++++---- core/drand_test.go | 12 ++++++---- core/util_test.go | 4 ++-- demo/node/node_inprocess.go | 9 +++++--- demo/node/node_subprocess.go | 6 ++--- demo/node/proposal_file.go | 1 + dkg/state_machine_test.go | 9 ++++---- entropy/entropy_test.go | 19 +++++++++------- http/server.go | 2 +- lp2p/relaynode_test.go | 2 +- metrics/metrics.go | 2 +- net/client_grpc.go | 11 +++++---- net/control.go | 24 +++++++++---------- net/gateway.go | 2 +- net/gateway_test.go | 2 +- net/listener.go | 2 +- test/api/serve.go | 5 ++-- test/dbtest.go | 2 +- test/mock/grpcserver.go | 18 +++++++-------- test/net/empty_server.go | 38 +++++++++++++++---------------- test/test-integration/go.mod | 1 + util/parsers.go | 1 + 37 files changed, 124 insertions(+), 111 deletions(-) diff --git a/chain/beacon/node.go b/chain/beacon/node.go index d6057d839..7506e199c 100644 --- a/chain/beacon/node.go +++ b/chain/beacon/node.go @@ -44,7 +44,7 @@ type Handler struct { conf *Config // to communicate with other drand peers client net.ProtocolClient - // keeps the cryptographic info (group share etc) + // keeps the cryptographic info (group share etc.) crypto *vault.Vault // main logic that treats incoming packet / new beacons created chain *chainStore @@ -446,7 +446,7 @@ func (h *Handler) run(startTime int64) { // Since that last node is late, nodes must now hurry up to do // the next beacons in time -> we run the next beacon now // already. If that next beacon is created soon after, this - // channel will trigger again etc until we arrive at the correct + // channel will trigger again etc. until we arrive at the correct // round. go func(c roundInfo, latest chain.Beacon) { defer span.End() diff --git a/chain/beacon/sync_manager.go b/chain/beacon/sync_manager.go index fb86dd2d4..cebd171ec 100644 --- a/chain/beacon/sync_manager.go +++ b/chain/beacon/sync_manager.go @@ -172,7 +172,7 @@ func (s *SyncManager) Run() { // -> time to start a new sync cancel() ctx, cancel = context.WithCancel(s.ctx) - //nolint + //nolint:errcheck // TODO: Handle this go s.Sync(ctx, request) } case <-s.newSync: diff --git a/client/empty.go b/client/empty.go index 0e7cf36dd..79756b86d 100644 --- a/client/empty.go +++ b/client/empty.go @@ -25,7 +25,7 @@ func (m *emptyClient) String() string { return emptyClientStringerValue } -func (m *emptyClient) Info(ctx context.Context) (*chain.Info, error) { +func (m *emptyClient) Info(_ context.Context) (*chain.Info, error) { return m.i, nil } @@ -33,11 +33,11 @@ func (m *emptyClient) RoundAt(t time.Time) uint64 { return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) } -func (m *emptyClient) Get(ctx context.Context, round uint64) (Result, error) { +func (m *emptyClient) Get(_ context.Context, _ uint64) (Result, error) { return nil, errEmptyClientUnsupportedGet } -func (m *emptyClient) Watch(ctx context.Context) <-chan Result { +func (m *emptyClient) Watch(_ context.Context) <-chan Result { ch := make(chan Result, 1) close(ch) return ch diff --git a/client/http/http.go b/client/http/http.go index 1d5c7c7bd..0953e2e83 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -242,7 +242,7 @@ func (h *httpClient) String() string { return fmt.Sprintf("HTTP(%q)", h.root) } -// Implement textMarshaller +// MarshalText implements encoding.TextMarshaller interface func (h *httpClient) MarshalText() ([]byte, error) { return json.Marshal(h.String()) } @@ -406,7 +406,7 @@ func (h *httpClient) Watch(ctx context.Context) <-chan client.Result { } // Info returns information about the chain. -func (h *httpClient) Info(ctx context.Context) (*chain.Info, error) { +func (h *httpClient) Info(_ context.Context) (*chain.Info, error) { return h.chainInfo, nil } diff --git a/client/interface.go b/client/interface.go index 02f50d407..1f5631789 100644 --- a/client/interface.go +++ b/client/interface.go @@ -30,6 +30,7 @@ type Client interface { // Close will halt the client, any background processes it runs and any // in-flight Get, Watch or Info requests. Behavior for usage of the client // after Close is called is undefined. + io.Closer } diff --git a/client/mock_test.go b/client/mock_test.go index 83551fd40..7ef568167 100644 --- a/client/mock_test.go +++ b/client/mock_test.go @@ -85,7 +85,7 @@ func (m *MockClient) Watch(ctx context.Context) <-chan Result { return ch } -func (m *MockClient) Info(ctx context.Context) (*chain.Info, error) { +func (m *MockClient) Info(_ context.Context) (*chain.Info, error) { if m.OptionalInfo != nil { return m.OptionalInfo, nil } @@ -127,7 +127,7 @@ func (m *MockInfoClient) String() string { return "MockInfo" } -func (m *MockInfoClient) Info(ctx context.Context) (*chain.Info, error) { +func (m *MockInfoClient) Info(_ context.Context) (*chain.Info, error) { return m.i, nil } @@ -135,11 +135,11 @@ func (m *MockInfoClient) RoundAt(t time.Time) uint64 { return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) } -func (m *MockInfoClient) Get(ctx context.Context, round uint64) (Result, error) { +func (m *MockInfoClient) Get(_ context.Context, _ uint64) (Result, error) { return nil, errors.New("not supported (mock info client get)") } -func (m *MockInfoClient) Watch(ctx context.Context) <-chan Result { +func (m *MockInfoClient) Watch(_ context.Context) <-chan Result { ch := make(chan Result, 1) close(ch) return ch diff --git a/client/optimizing.go b/client/optimizing.go index 1bf52419e..7d09ae1be 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -583,21 +583,21 @@ func (ws *watchState) closeSlowest() { func (ws *watchState) nextUnwatched() Client { clients := ws.optimizer.fastestClients() -CLIENT_LOOP: +ClientLoop: for _, c := range clients { for _, a := range ws.active { if c == a.Client { - continue CLIENT_LOOP + continue ClientLoop } } for _, f := range ws.failed { if c == f.Client { - continue CLIENT_LOOP + continue ClientLoop } } for _, p := range ws.protected { if c == p.Client { - continue CLIENT_LOOP + continue ClientLoop } } return c diff --git a/cmd/client/lib/cli_test.go b/cmd/client/lib/cli_test.go index 55d170752..9ca499d84 100644 --- a/cmd/client/lib/cli_test.go +++ b/cmd/client/lib/cli_test.go @@ -124,7 +124,7 @@ func TestClientLibGroupConfJSON(t *testing.T) { defer cancel() var b bytes.Buffer - info.ToJSON(&b, nil) + require.NoError(t, info.ToJSON(&b, nil)) infoPath := filepath.Join(t.TempDir(), "info.json") diff --git a/cmd/drand-cli/cli.go b/cmd/drand-cli/cli.go index 5724b3f69..14fc9e6c6 100644 --- a/cmd/drand-cli/cli.go +++ b/cmd/drand-cli/cli.go @@ -1082,7 +1082,7 @@ func deleteBeaconCmd(c *cli.Context, l log.Logger) error { return fmt.Errorf("beacon id [%s] - given round is ahead of the chain: %d", beaconID, lastBeacon.Round) } if verbose { - fmt.Printf("beacon id [%s] - planning to delete %d beacons \n", beaconID, (lastBeacon.Round - startRound)) + fmt.Printf("beacon id [%s] - planning to delete %d beacons \n", beaconID, lastBeacon.Round-startRound) } for round := startRound; round <= lastBeacon.Round; round++ { diff --git a/cmd/drand-cli/cli_test.go b/cmd/drand-cli/cli_test.go index f1d21c903..197aa81b3 100644 --- a/cmd/drand-cli/cli_test.go +++ b/cmd/drand-cli/cli_test.go @@ -461,7 +461,7 @@ func TestStartWithoutGroup(t *testing.T) { }) require.NoError(t, err) - // have to close it afterwards or starting the node will hang + // Have to close it afterwards or starting the node will become unrespondive err = dStore.Close() require.NoError(t, err) diff --git a/cmd/drand-cli/proposal_file.go b/cmd/drand-cli/proposal_file.go index 16fc4b568..18cd9ab36 100644 --- a/cmd/drand-cli/proposal_file.go +++ b/cmd/drand-cli/proposal_file.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "github.com/BurntSushi/toml" + "github.com/drand/drand/protobuf/drand" ) diff --git a/cmd/relay-gossip/main.go b/cmd/relay-gossip/main.go index 8f7c8ebf8..a4615db68 100644 --- a/cmd/relay-gossip/main.go +++ b/cmd/relay-gossip/main.go @@ -6,7 +6,7 @@ import ( "os" "path" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/libp2p/go-libp2p/core/peer" "github.com/urfave/cli/v2" @@ -96,7 +96,7 @@ var runCmd = &cli.Command{ if cctx.IsSet(metricsFlag.Name) { metricsListener := metrics.StartWithLogger(lg, cctx.String(metricsFlag.Name), pprof.WithProfile(), nil) defer metricsListener.Close() - if err := metrics.PrivateMetrics.Register(grpc_prometheus.DefaultClientMetrics); err != nil { + if err := metrics.PrivateMetrics.Register(grpcprometheus.DefaultClientMetrics); err != nil { return err } } diff --git a/cmd/relay/main.go b/cmd/relay/main.go index 1b8f2b396..82cf3ea9b 100644 --- a/cmd/relay/main.go +++ b/cmd/relay/main.go @@ -9,7 +9,7 @@ import ( "os" "github.com/gorilla/handlers" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" + grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/urfave/cli/v2" "github.com/drand/drand/cmd/client/lib" @@ -79,7 +79,7 @@ func Relay(c *cli.Context) error { metricsListener := metrics.StartWithLogger(cliLog, c.String(metricsFlag.Name), pprof.WithProfile(), nil) defer metricsListener.Close() - if err := metrics.PrivateMetrics.Register(grpc_prometheus.DefaultClientMetrics); err != nil { + if err := metrics.PrivateMetrics.Register(grpcprometheus.DefaultClientMetrics); err != nil { return err } } diff --git a/core/drand_beacon_control.go b/core/drand_beacon_control.go index 9125181d5..af31f53af 100644 --- a/core/drand_beacon_control.go +++ b/core/drand_beacon_control.go @@ -220,7 +220,7 @@ func (bp *BeaconProcess) Status(ctx context.Context, in *drand.StatusRequest) (* continue } if remoteAddress == bp.priv.Public.Addr { - // skipping ourself for the connectivity test + // Skipping ourselves for the connectivity test continue } diff --git a/core/drand_daemon_interceptors.go b/core/drand_daemon_interceptors.go index bee64b0c0..3dca07431 100644 --- a/core/drand_daemon_interceptors.go +++ b/core/drand_daemon_interceptors.go @@ -18,7 +18,7 @@ type MetadataGetter interface { } func (dd *DrandDaemon) NodeVersionValidator(ctx context.Context, req interface{}, - info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (response interface{}, err error) { + _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (response interface{}, err error) { ctx, span := metrics.NewSpan(ctx, "dd.NodeVersionValidator") defer span.End() @@ -61,7 +61,7 @@ func (dd *DrandDaemon) NodeVersionValidator(ctx context.Context, req interface{} } func (dd *DrandDaemon) NodeVersionStreamValidator(srv interface{}, ss grpc.ServerStream, - info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { reqWithContext, ok := srv.(MetadataGetter) if !ok { diff --git a/core/drand_proxy.go b/core/drand_proxy.go index df96243b2..1f8358c24 100644 --- a/core/drand_proxy.go +++ b/core/drand_proxy.go @@ -49,7 +49,7 @@ func (d *drandProxy) Watch(ctx context.Context) <-chan client.Result { go func() { err := d.r.PublicRandStream(&drand.PublicRandRequest{}, proxy) if err != nil { - proxy.Close(err) + proxy.Close() } }() return proxy.outgoing @@ -116,11 +116,12 @@ func (s *streamProxy) Send(next *drand.PublicRandResponse) error { } } -func (s *streamProxy) Close(err error) { +func (s *streamProxy) Close() { s.cancel() } /* implement the grpc stream interface. not used since messages passed directly. */ + func (s *streamProxy) SetHeader(metadata.MD) error { return nil } @@ -132,10 +133,10 @@ func (s *streamProxy) SetTrailer(metadata.MD) {} func (s *streamProxy) Context() context.Context { return peer.NewContext(s.ctx, &peer.Peer{Addr: &net.UnixAddr{}}) } -func (s *streamProxy) SendMsg(m interface{}) error { +func (s *streamProxy) SendMsg(_ interface{}) error { return nil } -func (s *streamProxy) RecvMsg(m interface{}) error { +func (s *streamProxy) RecvMsg(_ interface{}) error { return nil } diff --git a/core/drand_test.go b/core/drand_test.go index b08a59119..4a03b894c 100644 --- a/core/drand_test.go +++ b/core/drand_test.go @@ -192,7 +192,7 @@ func TestDrandDKGFresh(t *testing.T) { dt.CheckBeaconLength(t, dt.nodes, 3) t.Log("Check Beacon Public") - response := dt.CheckPublicBeacon(lastNode.addr, false) + response := dt.CheckPublicBeacon(ctx, lastNode.addr, false) require.Equal(t, uint64(2), response.Round) } @@ -352,6 +352,9 @@ func TestRunDKGReshareAbsentNodeForExecutionStart(t *testing.T) { // //nolint:funlen func TestRunDKGReshareTimeout(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + oldNodes, newNodes, oldThreshold := 3, 4, 2 beaconPeriod := 2 * time.Second offline := 1 @@ -388,7 +391,7 @@ func TestRunDKGReshareTimeout(t *testing.T) { for { dt.AdvanceMockClock(t, beaconPeriod) time.Sleep(sleepDuration) - dt.CheckPublicBeacon(dt.NodeAddresses(1, false)[0], false) + dt.CheckPublicBeacon(ctx, dt.NodeAddresses(1, false)[0], false) if dt.clock.Now().Unix() > resharedGroup.TransitionTime { break } @@ -404,8 +407,7 @@ func TestRunDKGReshareTimeout(t *testing.T) { rootID := root.priv.Public cm := root.opts.certmanager client := net.NewGrpcClientFromCertManagerWithLogger(testlogger.New(t), cm) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + resp, err := client.PublicRand(ctx, rootID, new(drand.PublicRandRequest)) require.NoError(t, err) @@ -1149,7 +1151,7 @@ func TestModifyingGroupFileManuallyDoesNotSegfault(t *testing.T) { store := key.NewFileStore(dir, beaconID) node.drand.store = store - // save the key pair, as this was done ephemerally inside of `NewDrandTestScenario` >.> + // save the key pair, as this was done ephemerally inside `NewDrandTestScenario` >.> err := store.SaveKeyPair(priv) require.NoError(t, err) diff --git a/core/util_test.go b/core/util_test.go index a2648c4a7..a7bc57d28 100644 --- a/core/util_test.go +++ b/core/util_test.go @@ -362,12 +362,12 @@ func (d *DrandTestScenario) CheckBeaconLength(t *testing.T, nodes []*MockNode, e } // CheckPublicBeacon looks if we can get the latest beacon on this node -func (d *DrandTestScenario) CheckPublicBeacon(nodeAddress string, newGroup bool) *drand.PublicRandResponse { +func (d *DrandTestScenario) CheckPublicBeacon(ctx context.Context, nodeAddress string, newGroup bool) *drand.PublicRandResponse { node := d.GetMockNode(nodeAddress, newGroup) dr := node.drand client := net.NewGrpcClientFromCertManagerWithLogger(dr.log, dr.opts.certmanager, dr.opts.grpcOpts...) - resp, err := client.PublicRand(context.TODO(), test.NewTLSPeer(dr.priv.Public.Addr), &drand.PublicRandRequest{}) + resp, err := client.PublicRand(ctx, test.NewTLSPeer(dr.priv.Public.Addr), &drand.PublicRandRequest{}) require.NoError(d.t, err) require.NotNil(d.t, resp) diff --git a/demo/node/node_inprocess.go b/demo/node/node_inprocess.go index 1807b0ccb..25f88d88c 100644 --- a/demo/node/node_inprocess.go +++ b/demo/node/node_inprocess.go @@ -306,7 +306,7 @@ func (l *LocalNode) AcceptReshare() error { return nil } -func (l *LocalNode) ChainInfo(group string) bool { +func (l *LocalNode) ChainInfo(_ string) bool { cl := l.ctrl() ci, err := cl.ChainInfo(l.beaconID) if err != nil { @@ -327,7 +327,7 @@ func (l *LocalNode) Ping() bool { return true } -func (l *LocalNode) GetBeacon(groupPath string, round uint64) (resp *drand.PublicRandResponse, cmd string) { +func (l *LocalNode) GetBeacon(_ string, round uint64) (resp *drand.PublicRandResponse, cmd string) { cert := "" if l.tls { cert = path.Join(l.base, fmt.Sprintf("server-%d.crt", l.i)) @@ -361,7 +361,10 @@ func (l *LocalNode) GetBeacon(groupPath string, round uint64) (resp *drand.Publi func (l *LocalNode) WriteCertificate(p string) { if l.tls { - exec.Command("cp", path.Join(l.base, fmt.Sprintf("server-%d.crt", l.i)), p).Run() + err := exec.Command("cp", path.Join(l.base, fmt.Sprintf("server-%d.crt", l.i)), p).Run() + if err != nil { + panic(err) + } } } diff --git a/demo/node/node_subprocess.go b/demo/node/node_subprocess.go index 3bc6509c9..6f6f4f8fb 100644 --- a/demo/node/node_subprocess.go +++ b/demo/node/node_subprocess.go @@ -252,7 +252,7 @@ func (n *NodeProc) Index() int { return n.i } -func (n *NodeProc) StartLeaderDKG(thr int, beaconOffset int, joiners []*drand.Participant) error { +func (n *NodeProc) StartLeaderDKG(thr int, _ int, joiners []*drand.Participant) error { proposal := ProposalFile{ Joining: joiners, } @@ -325,7 +325,7 @@ func (n *NodeProc) JoinReshare(oldGroup key.Group) error { return nil } -func (n *NodeProc) StartLeaderReshare(thr int, transitionTime time.Time, beaconOffset int, joiners []*drand.Participant, remainers []*drand.Participant, leavers []*drand.Participant) error { +func (n *NodeProc) StartLeaderReshare(thr int, transitionTime time.Time, _ int, joiners []*drand.Participant, remainers []*drand.Participant, leavers []*drand.Participant) error { proposalFileName := "proposal.toml" proposal := ProposalFile{ Joining: joiners, @@ -395,7 +395,7 @@ func (n *NodeProc) GetGroup() *key.Group { return group } -func (n *NodeProc) ChainInfo(group string) bool { +func (n *NodeProc) ChainInfo(_ string) bool { args := []string{"get", "chain-info"} if n.tls { args = append(args, pair("--tls-cert", n.certPath)...) diff --git a/demo/node/proposal_file.go b/demo/node/proposal_file.go index 416e0c171..9ada6007f 100644 --- a/demo/node/proposal_file.go +++ b/demo/node/proposal_file.go @@ -6,6 +6,7 @@ import ( "os" "github.com/BurntSushi/toml" + cli "github.com/drand/drand/cmd/drand-cli" "github.com/drand/drand/protobuf/drand" ) diff --git a/dkg/state_machine_test.go b/dkg/state_machine_test.go index 8a2fc6340..805495dca 100644 --- a/dkg/state_machine_test.go +++ b/dkg/state_machine_test.go @@ -6,14 +6,13 @@ import ( "testing" "time" - "github.com/drand/drand/crypto" - - "github.com/drand/drand/util" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/drand/drand/crypto" "github.com/drand/drand/key" "github.com/drand/drand/protobuf/drand" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/types/known/timestamppb" + "github.com/drand/drand/util" ) // alice, bob and carol are the actors for all the tests diff --git a/entropy/entropy_test.go b/entropy/entropy_test.go index d16bfc593..c3b1a41f8 100644 --- a/entropy/entropy_test.go +++ b/entropy/entropy_test.go @@ -4,6 +4,8 @@ import ( "bytes" "os" "testing" + + "github.com/stretchr/testify/require" ) func TestGetRandomness32BytesDefault(t *testing.T) { @@ -38,14 +40,16 @@ func TestEntropyRead(t *testing.T) { panic(err) } - file.Chmod(0740) + require.NoError(t, file.Chmod(0740)) _, err = file.WriteString("#!/bin/sh\necho Hey, good morning, Monstropolis") if err != nil { panic(err) } file.Close() - defer os.Remove("./veryrandom.sh") + t.Cleanup(func() { + os.Remove("./veryrandom.sh") + }) execRand := "./veryrandom.sh" entropyReader := NewScriptReader(execRand) @@ -58,19 +62,18 @@ func TestEntropyRead(t *testing.T) { func TestEntropyReadSmallExec(t *testing.T) { file, err := os.Create("./veryrandom2.sh") + require.NoError(t, err) - if err != nil { - panic(err) - } - - file.Chmod(0740) + require.NoError(t, file.Chmod(0740)) _, err = file.WriteString("#!/bin/sh\necho Hey") if err != nil { panic(err) } file.Close() - defer os.Remove("./veryrandom2.sh") + t.Cleanup(func() { + os.Remove("./veryrandom2.sh") + }) execRand := "./veryrandom2.sh" entropyReader := NewScriptReader(execRand) diff --git a/http/server.go b/http/server.go index 2e5dd61dd..c20edcaf9 100644 --- a/http/server.go +++ b/http/server.go @@ -576,7 +576,7 @@ func (h *DrandHandler) Health(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(b) } -func (h *DrandHandler) ChainHashes(w http.ResponseWriter, r *http.Request) { +func (h *DrandHandler) ChainHashes(w http.ResponseWriter, _ *http.Request) { chainHashes := make([]string, 0) for chainHash := range h.beacons { if chainHash != common.DefaultChainHash { diff --git a/lp2p/relaynode_test.go b/lp2p/relaynode_test.go index 9ce3986a6..ef7694b9b 100644 --- a/lp2p/relaynode_test.go +++ b/lp2p/relaynode_test.go @@ -21,7 +21,7 @@ type mockClient struct { watchF func(context.Context) <-chan client.Result } -func (c *mockClient) Get(ctx context.Context, round uint64) (client.Result, error) { +func (c *mockClient) Get(_ context.Context, _ uint64) (client.Result, error) { return nil, errors.New("unsupported") } diff --git a/metrics/metrics.go b/metrics/metrics.go index 288211f48..353d9e5e5 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -352,7 +352,7 @@ func RegisterClientMetrics(r prometheus.Registerer) error { return nil } -// GroupHandlers abstracts a helper for relaying http requests to a group peer +// Handler abstracts a helper for relaying http requests to a group peer type Handler func(ctx context.Context, addr string) (http.Handler, error) // Start starts a prometheus metrics server with debug endpoints. diff --git a/net/client_grpc.go b/net/client_grpc.go index f431646ba..3f1d40893 100644 --- a/net/client_grpc.go +++ b/net/client_grpc.go @@ -94,7 +94,7 @@ func (g *grpcClient) getTimeoutContext(ctx context.Context) (context.Context, co } func (g *grpcClient) GetIdentity(ctx context.Context, p Peer, - in *drand.IdentityRequest, opts ...CallOption) (*drand.IdentityResponse, error) { + in *drand.IdentityRequest, _ ...CallOption) (*drand.IdentityResponse, error) { var resp *drand.IdentityResponse c, err := g.conn(ctx, p) if err != nil { @@ -120,12 +120,13 @@ func (g *grpcClient) PublicRand(ctx context.Context, p Peer, in *drand.PublicRan const grpcClientRandStreamBacklog = 10 -// XXX move that to core/ client +// PublicRandStream allows clients to stream randomness +// TODO: move that to core/ client func (g *grpcClient) PublicRandStream( ctx context.Context, p Peer, in *drand.PublicRandRequest, - opts ...CallOption) (chan *drand.PublicRandResponse, error) { + _ ...CallOption) (chan *drand.PublicRandResponse, error) { var outCh = make(chan *drand.PublicRandResponse, grpcClientRandStreamBacklog) c, err := g.conn(ctx, p) if err != nil { @@ -193,7 +194,7 @@ func (g *grpcClient) PartialBeacon(ctx context.Context, p Peer, in *drand.Partia // MaxSyncBuffer is the maximum number of queued rounds when syncing const MaxSyncBuffer = 500 -func (g *grpcClient) SyncChain(ctx context.Context, p Peer, in *drand.SyncRequest, opts ...CallOption) (chan *drand.BeaconPacket, error) { +func (g *grpcClient) SyncChain(ctx context.Context, p Peer, in *drand.SyncRequest, _ ...CallOption) (chan *drand.BeaconPacket, error) { resp := make(chan *drand.BeaconPacket, MaxSyncBuffer) c, err := g.conn(ctx, p) if err != nil { @@ -360,7 +361,7 @@ func (g *grpcClient) Stop() { g.Lock() defer g.Unlock() for _, c := range g.conns { - c.Close() + _ = c.Close() } g.conns = make(map[string]*grpc.ClientConn) } diff --git a/net/control.go b/net/control.go index 80dc02d1b..06f91dbbf 100644 --- a/net/control.go +++ b/net/control.go @@ -20,7 +20,7 @@ import ( const grpcDefaultIPNetwork = "tcp" -// ControlListener is used to keep state of the connections of our drand instance +// ControlListener is used to keep state for the connections of our drand instance type ControlListener struct { log log.Logger conns *grpc.Server @@ -32,7 +32,7 @@ func NewGRPCListener(s Service, controlAddr string) (ControlListener, error) { return NewGRPCListenerWithLogger(l, s, controlAddr) } -// NewTCPGrpcControlListenerWithLogger registers the pairing between a ControlServer and a grpc server +// NewGRPCListenerWithLogger registers the pairing between a ControlServer and a grpc server func NewGRPCListenerWithLogger(l log.Logger, s Service, controlAddr string) (ControlListener, error) { grpcServer := grpc.NewServer() lis, err := newListener(controlAddr) @@ -147,24 +147,22 @@ func (c *ControlClient) Ping() error { return err } -// LoadBeacon +// LoadBeacon loads the beacon details func (c *ControlClient) LoadBeacon(beaconID string) (*control.LoadBeaconResponse, error) { metadata := protoCommon.Metadata{ NodeVersion: c.version.ToProto(), BeaconID: beaconID, } - resp, err := c.client.LoadBeacon(ctx.Background(), &control.LoadBeaconRequest{Metadata: &metadata}) - return resp, err + return c.client.LoadBeacon(ctx.Background(), &control.LoadBeaconRequest{Metadata: &metadata}) } -// ListBeaconIDs +// ListBeaconIDs returns a list of all beacon ids func (c *ControlClient) ListBeaconIDs() (*control.ListBeaconIDsResponse, error) { metadata := protoCommon.Metadata{ NodeVersion: c.version.ToProto(), } - resp, err := c.client.ListBeaconIDs(ctx.Background(), &control.ListBeaconIDsRequest{Metadata: &metadata}) - return resp, err + return c.client.ListBeaconIDs(ctx.Background(), &control.ListBeaconIDsRequest{Metadata: &metadata}) } // Status gets the current daemon status @@ -173,16 +171,14 @@ func (c *ControlClient) Status(beaconID string) (*control.StatusResponse, error) NodeVersion: c.version.ToProto(), BeaconID: beaconID, } - resp, err := c.client.Status(ctx.Background(), &control.StatusRequest{Metadata: &metadata}) - return resp, err + return c.client.Status(ctx.Background(), &control.StatusRequest{Metadata: &metadata}) } // ListSchemes responds with the list of ids for the available schemes func (c *ControlClient) ListSchemes() (*control.ListSchemesResponse, error) { metadata := protoCommon.NewMetadata(c.version.ToProto()) - resp, err := c.client.ListSchemes(ctx.Background(), &control.ListSchemesRequest{Metadata: metadata}) - return resp, err + return c.client.ListSchemes(ctx.Background(), &control.ListSchemesRequest{Metadata: metadata}) } // PublicKey returns the public key of the remote node @@ -284,6 +280,7 @@ func (c *ControlClient) StartCheckChain(cc ctx.Context, hashStr string, nodes [] } } }() + return outCh, errCh, nil } @@ -343,6 +340,7 @@ func (c *ControlClient) StartFollowChain(cc ctx.Context, } } }() + return outCh, errCh, nil } @@ -364,7 +362,7 @@ type DefaultControlServer struct { } // PingPong sends a ping to the server -func (s *DefaultControlServer) PingPong(c ctx.Context, in *control.Ping) (*control.Pong, error) { +func (s *DefaultControlServer) PingPong(_ ctx.Context, _ *control.Ping) (*control.Pong, error) { return &control.Pong{}, nil } diff --git a/net/gateway.go b/net/gateway.go index c735fbc58..2035775ce 100644 --- a/net/gateway.go +++ b/net/gateway.go @@ -102,7 +102,7 @@ func (g *PublicGateway) StopAll(ctx context.Context) { func NewRESTPublicGateway( ctx context.Context, listen, certPath, keyPath string, - certs *CertManager, + _ *CertManager, handler http.Handler, insecure bool) (*PublicGateway, error) { l, err := NewRESTListenerForPublic(ctx, listen, certPath, keyPath, handler, insecure) diff --git a/net/gateway_test.go b/net/gateway_test.go index 92a90584a..8e07555b9 100644 --- a/net/gateway_test.go +++ b/net/gateway_test.go @@ -40,7 +40,7 @@ func (t *testRandomnessServer) PublicRand(context.Context, *drand.PublicRandRequ return &drand.PublicRandResponse{Round: t.round}, nil } -func (t *testRandomnessServer) Group(context.Context, *drand.GroupRequest) (*drand.GroupPacket, error) { +func (t *testRandomnessServer) Group(_ context.Context, _ *drand.GroupRequest) (*drand.GroupPacket, error) { return nil, nil } func (t *testRandomnessServer) Home(context.Context, *drand.HomeRequest) (*drand.HomeResponse, error) { diff --git a/net/listener.go b/net/listener.go index c95156653..3ab1fa7f9 100644 --- a/net/listener.go +++ b/net/listener.go @@ -227,7 +227,7 @@ func (g *grpcListener) Start() { }() } -func (g *grpcListener) Stop(ctx context.Context) { +func (g *grpcListener) Stop(_ context.Context) { g.grpcServer.Stop() _ = g.lis.Close() } diff --git a/test/api/serve.go b/test/api/serve.go index 520c708b8..ef28e0bda 100644 --- a/test/api/serve.go +++ b/test/api/serve.go @@ -22,6 +22,7 @@ type TestJSON struct { } func main() { + ctx := context.Background() lg := log.New(nil, log.DebugLevel, false) sch, err := crypto.GetSchemeFromEnv() if err != nil { @@ -29,11 +30,11 @@ func main() { } clk := clock.NewRealClock() listener, server := mock.NewMockGRPCPublicServer(nil, lg, serve, true, sch, clk) - resp, err := server.PublicRand(context.TODO(), &drand.PublicRandRequest{}) + resp, err := server.PublicRand(ctx, &drand.PublicRandRequest{}) if err != nil { panic(err) } - ci, err := server.ChainInfo(context.TODO(), &drand.ChainInfoRequest{}) + ci, err := server.ChainInfo(ctx, &drand.ChainInfoRequest{}) if err != nil { panic(err) } diff --git a/test/dbtest.go b/test/dbtest.go index 542ca6a5f..82c92e670 100644 --- a/test/dbtest.go +++ b/test/dbtest.go @@ -39,7 +39,7 @@ func StartPGDB() (*Container, error) { // StopPGDB stops a running database instance. func StopPGDB(c *Container) { - StopContainer(c.ID) + _ = StopContainer(c.ID) fmt.Println("Stopped:", c.ID) } diff --git a/test/mock/grpcserver.go b/test/mock/grpcserver.go index 427829a62..8f53f963c 100644 --- a/test/mock/grpcserver.go +++ b/test/mock/grpcserver.go @@ -80,7 +80,7 @@ func (s *Server) ChainInfo(context.Context, *drand.ChainInfoRequest) (*drand.Cha } // PublicRand implements net.Service -func (s *Server) PublicRand(c context.Context, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { +func (s *Server) PublicRand(_ context.Context, in *drand.PublicRandRequest) (*drand.PublicRandResponse, error) { s.l.Lock() defer s.l.Unlock() prev := decodeHex(s.d.PreviousSignature) @@ -100,7 +100,7 @@ func (s *Server) PublicRand(c context.Context, in *drand.PublicRandRequest) (*dr } // PublicRandStream is part of the public drand service. -func (s *Server) PublicRandStream(req *drand.PublicRandRequest, stream drand.Public_PublicRandStreamServer) error { +func (s *Server) PublicRandStream(_ *drand.PublicRandRequest, stream drand.Public_PublicRandStreamServer) error { streamDone := make(chan error, 1) s.l.Lock() s.streamDone = streamDone @@ -363,31 +363,31 @@ func (s *Server) Join(ctx context.Context, options *drand.JoinOptions) (*drand.E return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartNetwork(ctx context.Context, in *drand.FirstProposalOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartNetwork(_ context.Context, _ *drand.FirstProposalOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartProposal(ctx context.Context, in *drand.ProposalOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartProposal(_ context.Context, _ *drand.ProposalOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartAbort(ctx context.Context, in *drand.AbortOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartAbort(_ context.Context, _ *drand.AbortOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartExecute(ctx context.Context, in *drand.ExecutionOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartExecute(_ context.Context, _ *drand.ExecutionOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartAccept(ctx context.Context, in *drand.AcceptOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartAccept(_ context.Context, _ *drand.AcceptOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) StartReject(ctx context.Context, in *drand.RejectOptions) (*drand.EmptyResponse, error) { +func (s *Server) StartReject(_ context.Context, _ *drand.RejectOptions) (*drand.EmptyResponse, error) { return nil, errors.New("unimplemented for mock server") } -func (s *Server) DKGStatus(ctx context.Context, in *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { +func (s *Server) DKGStatus(_ context.Context, _ *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { return nil, errors.New("unimplemented for mock server") } diff --git a/test/net/empty_server.go b/test/net/empty_server.go index c04fb099c..da246cdef 100644 --- a/test/net/empty_server.go +++ b/test/net/empty_server.go @@ -12,7 +12,7 @@ import ( type EmptyServer struct{} // GetIdentity returns the identity of the server -func (s *EmptyServer) GetIdentity(ctx context.Context, in *drand.IdentityRequest) (*drand.IdentityResponse, error) { +func (s *EmptyServer) GetIdentity(_ context.Context, _ *drand.IdentityRequest) (*drand.IdentityResponse, error) { return nil, nil } @@ -106,7 +106,7 @@ func (s *EmptyServer) Shutdown(context.Context, *drand.ShutdownRequest) (*drand. return nil, nil } -// ReloadBeacon is an empty implementation +// LoadBeacon is an empty implementation func (s *EmptyServer) LoadBeacon(context.Context, *drand.LoadBeaconRequest) (*drand.LoadBeaconResponse, error) { return nil, nil } @@ -121,65 +121,65 @@ func (s *EmptyServer) BackupDatabase(context.Context, *drand.BackupDBRequest) (* return nil, nil } -// Shutdown is an empty implementation -func (s *EmptyServer) NodeVersionValidator(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (response interface{}, err error) { +// NodeVersionValidator is an empty implementation +func (s *EmptyServer) NodeVersionValidator(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (response interface{}, err error) { return handler(ctx, req) } -// Shutdown is an empty implementation -func (s *EmptyServer) NodeVersionStreamValidator(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { +// NodeVersionStreamValidator is an empty implementation +func (s *EmptyServer) NodeVersionStreamValidator(srv interface{}, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { return handler(srv, ss) } -func (s *EmptyServer) Accept(_ context.Context, acceptance *drand.AcceptProposal) (*drand.EmptyResponse, error) { +func (s *EmptyServer) Accept(_ context.Context, _ *drand.AcceptProposal) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) Reject(_ context.Context, rejection *drand.RejectProposal) (*drand.EmptyResponse, error) { +func (s *EmptyServer) Reject(_ context.Context, _ *drand.RejectProposal) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) Propose(_ context.Context, proposal *drand.ProposalTerms) (*drand.EmptyResponse, error) { +func (s *EmptyServer) Propose(_ context.Context, _ *drand.ProposalTerms) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) Abort(_ context.Context, abort *drand.AbortDKG) (*drand.EmptyResponse, error) { +func (s *EmptyServer) Abort(_ context.Context, _ *drand.AbortDKG) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) Execute(_ context.Context, kickoff *drand.StartExecution) (*drand.EmptyResponse, error) { +func (s *EmptyServer) Execute(_ context.Context, _ *drand.StartExecution) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartNetwork(_ context.Context, options *drand.FirstProposalOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartNetwork(_ context.Context, _ *drand.FirstProposalOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartProposal(_ context.Context, options *drand.ProposalOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartProposal(_ context.Context, _ *drand.ProposalOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartJoin(_ context.Context, options *drand.JoinOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartJoin(_ context.Context, _ *drand.JoinOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartAbort(_ context.Context, options *drand.AbortOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartAbort(_ context.Context, _ *drand.AbortOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartExecute(_ context.Context, options *drand.ExecutionOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartExecute(_ context.Context, _ *drand.ExecutionOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartAccept(_ context.Context, options *drand.AcceptOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartAccept(_ context.Context, _ *drand.AcceptOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) StartReject(_ context.Context, options *drand.RejectOptions) (*drand.EmptyResponse, error) { +func (s *EmptyServer) StartReject(_ context.Context, _ *drand.RejectOptions) (*drand.EmptyResponse, error) { return nil, nil } -func (s *EmptyServer) DKGStatus(_ context.Context, request *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { +func (s *EmptyServer) DKGStatus(_ context.Context, _ *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { return nil, nil } diff --git a/test/test-integration/go.mod b/test/test-integration/go.mod index dd1abbef5..ee3366807 100644 --- a/test/test-integration/go.mod +++ b/test/test-integration/go.mod @@ -25,4 +25,5 @@ require ( google.golang.org/protobuf v1.28.1 // indirect ) +// This is is required to allow testing against the current code. replace github.com/drand/drand => ../../. diff --git a/util/parsers.go b/util/parsers.go index aec66e613..a109074e8 100644 --- a/util/parsers.go +++ b/util/parsers.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/BurntSushi/toml" + "github.com/drand/drand/key" ) From 468455243b960176ced76d8aa87109e3aa122972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Fri, 24 Mar 2023 21:53:44 +0200 Subject: [PATCH 4/9] Instrument the DKG code --- dkg/actions_active.go | 46 ++++++++++++++++++++++++++++++++++-------- dkg/actions_passive.go | 21 +++++++++++++++---- dkg/dkg_process.go | 7 +++++-- dkg/execution.go | 23 ++++++++++++++++----- dkg/network.go | 28 +++++++++++++++++++------ 5 files changed, 100 insertions(+), 25 deletions(-) diff --git a/dkg/actions_active.go b/dkg/actions_active.go index 61a419f19..22832a8d0 100644 --- a/dkg/actions_active.go +++ b/dkg/actions_active.go @@ -6,6 +6,7 @@ import ( "time" "github.com/drand/drand/key" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" @@ -19,6 +20,9 @@ import ( // accepting or rejecting a DKG, getting the status, etc. Both leader and follower interactions are contained herein. func (d *DKGProcess) StartNetwork(ctx context.Context, options *drand.FirstProposalOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartNetwork") + defer span.End() + beaconID := options.BeaconID d.log.Infow("Starting initial DKG", "beaconID", beaconID) @@ -64,7 +68,7 @@ func (d *DKGProcess) StartNetwork(ctx context.Context, options *drand.FirstPropo } sendProposalAndStoreNextState := func() error { - err := d.network.Send(me, nextState.Joining, func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + err := d.network.Send(ctx, me, nextState.Joining, func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { return client.Propose(ctx, peer, &terms) }) if err != nil { @@ -103,7 +107,10 @@ func (d *DKGProcess) attemptAbort( participants []*drand.Participant, beaconID string, ) error { - return d.network.Send(me, participants, func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.attemptAbort") + defer span.End() + + return d.network.Send(ctx, me, participants, func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { return client.Abort( ctx, peer, @@ -114,6 +121,9 @@ func (d *DKGProcess) attemptAbort( } func (d *DKGProcess) StartProposal(ctx context.Context, options *drand.ProposalOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartProposal") + defer span.End() + beaconID := options.BeaconID d.log.Infow("Proposing DKG", "beaconID", beaconID) @@ -153,9 +163,10 @@ func (d *DKGProcess) StartProposal(ctx context.Context, options *drand.ProposalO sendProposalToAllAndStoreState := func() error { // we send the proposal to joiners and remainers and error if they don't respond err = d.network.Send( + ctx, me, util.Concat(nextState.Joining, nextState.Remaining), - func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { return client.Propose(ctx, peer, &terms) }, ) @@ -166,7 +177,7 @@ func (d *DKGProcess) StartProposal(ctx context.Context, options *drand.ProposalO // we make a best effort attempt to send the proposal to the leaver, but if their node is e.g. turned off then // we ignore the error if len(nextState.Leaving) > 0 { - err = d.network.Send(me, nextState.Leaving, func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + err = d.network.Send(ctx, me, nextState.Leaving, func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { return client.Propose(ctx, peer, &terms) }) @@ -194,6 +205,9 @@ func (d *DKGProcess) StartProposal(ctx context.Context, options *drand.ProposalO } func (d *DKGProcess) StartAbort(ctx context.Context, options *drand.AbortOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartAbort") + defer span.End() + beaconID := options.BeaconID d.log.Infow("Aborting DKG", "beaconID", beaconID) @@ -230,6 +244,9 @@ func (d *DKGProcess) StartAbort(ctx context.Context, options *drand.AbortOptions } func (d *DKGProcess) StartExecute(ctx context.Context, options *drand.ExecutionOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartExecute") + defer span.End() + beaconID := options.BeaconID stateTransition := func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -242,9 +259,10 @@ func (d *DKGProcess) StartExecute(ctx context.Context, options *drand.ExecutionO callback := func(me *drand.Participant, nextState *DBState) error { allParticipants := util.Concat(nextState.Joining, nextState.Remaining, nextState.Leaving) return d.network.SendIgnoringConnectionError( + ctx, me, allParticipants, - func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { return client.Execute(ctx, peer, &drand.StartExecution{ Metadata: &drand.DKGMetadata{ BeaconID: beaconID, @@ -273,7 +291,7 @@ func (d *DKGProcess) StartExecute(ctx context.Context, options *drand.ExecutionO time.Sleep(d.config.KickoffGracePeriod) // copy this to avoid any data races with kyber dkgConfigCopy := *dkgConfig - err := d.executeAndFinishDKG(beaconID, dkgConfigCopy) + err := d.executeAndFinishDKG(ctx, beaconID, dkgConfigCopy) if err != nil { d.log.Errorw("there was an error during the DKG!", "beaconID", beaconID, "error", err) } @@ -282,7 +300,10 @@ func (d *DKGProcess) StartExecute(ctx context.Context, options *drand.ExecutionO return responseOrError(err) } -func (d *DKGProcess) StartJoin(_ context.Context, options *drand.JoinOptions) (*drand.EmptyResponse, error) { +func (d *DKGProcess) StartJoin(ctx context.Context, options *drand.JoinOptions) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.StartJoin") + defer span.End() + beaconID := options.BeaconID err := d.executeAction("Joining DKG", beaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -306,6 +327,9 @@ func (d *DKGProcess) StartJoin(_ context.Context, options *drand.JoinOptions) (* // //nolint:dupl func (d *DKGProcess) StartAccept(ctx context.Context, options *drand.AcceptOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartAccept") + defer span.End() + beaconID := options.BeaconID stateTransition := func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -334,6 +358,9 @@ func (d *DKGProcess) StartAccept(ctx context.Context, options *drand.AcceptOptio // //nolint:dupl func (d *DKGProcess) StartReject(ctx context.Context, options *drand.RejectOptions) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.StartReject") + defer span.End() + beaconID := options.BeaconID stateTransition := func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -356,7 +383,10 @@ func (d *DKGProcess) StartReject(ctx context.Context, options *drand.RejectOptio return responseOrError(err) } -func (d *DKGProcess) DKGStatus(_ context.Context, request *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { +func (d *DKGProcess) DKGStatus(ctx context.Context, request *drand.DKGStatusRequest) (*drand.DKGStatusResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.DKGStatus") + defer span.End() + finished, err := d.store.GetFinished(request.BeaconID) if err != nil { return nil, err diff --git a/dkg/actions_passive.go b/dkg/actions_passive.go index 255c1c778..06dc20096 100644 --- a/dkg/actions_passive.go +++ b/dkg/actions_passive.go @@ -5,13 +5,17 @@ import ( "errors" "time" + "github.com/drand/drand/metrics" "github.com/drand/drand/protobuf/drand" ) // actions_passive contains all internal messaging between nodes triggered by the protocol - things it does automatically // upon receiving messages from other nodes: storing proposals, aborting when the leader aborts, etc -func (d *DKGProcess) Propose(_ context.Context, proposal *drand.ProposalTerms) (*drand.EmptyResponse, error) { +func (d *DKGProcess) Propose(ctx context.Context, proposal *drand.ProposalTerms) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.DKGStatus") + defer span.End() + err := d.executeAction("DKG proposal", proposal.BeaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { // strictly speaking, we don't actually _know_ this proposal came from the leader here // it will have to be verified by signing later @@ -21,7 +25,10 @@ func (d *DKGProcess) Propose(_ context.Context, proposal *drand.ProposalTerms) ( return responseOrError(err) } -func (d *DKGProcess) Accept(_ context.Context, acceptance *drand.AcceptProposal) (*drand.EmptyResponse, error) { +func (d *DKGProcess) Accept(ctx context.Context, acceptance *drand.AcceptProposal) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.Accept") + defer span.End() + err := d.executeAction("DKG acceptance", acceptance.Metadata.BeaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { return current.ReceivedAcceptance(me, acceptance.Acceptor) }) @@ -37,7 +44,10 @@ func (d *DKGProcess) Reject(_ context.Context, rejection *drand.RejectProposal) return responseOrError(err) } -func (d *DKGProcess) Abort(_ context.Context, abort *drand.AbortDKG) (*drand.EmptyResponse, error) { +func (d *DKGProcess) Abort(ctx context.Context, abort *drand.AbortDKG) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.Abort") + defer span.End() + err := d.executeAction("abort DKG", abort.Metadata.BeaconID, func(_ *drand.Participant, current *DBState) (*DBState, error) { return current.Aborted() }) @@ -46,6 +56,9 @@ func (d *DKGProcess) Abort(_ context.Context, abort *drand.AbortDKG) (*drand.Emp } func (d *DKGProcess) Execute(ctx context.Context, kickoff *drand.StartExecution) (*drand.EmptyResponse, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.Execute") + defer span.End() + beaconID := kickoff.Metadata.BeaconID err := d.executeAction("DKG execution", beaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -69,7 +82,7 @@ func (d *DKGProcess) Execute(ctx context.Context, kickoff *drand.StartExecution) time.Sleep(d.config.KickoffGracePeriod) // copy this to avoid any data races with kyber dkgConfigCopy := *dkgConfig - err := d.executeAndFinishDKG(beaconID, dkgConfigCopy) + err := d.executeAndFinishDKG(ctx, beaconID, dkgConfigCopy) if err != nil { d.log.Errorw("there was an error during the DKG execution!", "beaconID", beaconID, "error", err) } diff --git a/dkg/dkg_process.go b/dkg/dkg_process.go index bb7d78c28..0408c4fd7 100644 --- a/dkg/dkg_process.go +++ b/dkg/dkg_process.go @@ -1,6 +1,7 @@ package dkg import ( + "context" "sync" "time" @@ -76,14 +77,16 @@ type Store interface { type Network interface { Send( + ctx context.Context, from *drand.Participant, to []*drand.Participant, - action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error), + action SendAction, ) error SendIgnoringConnectionError( + ctx context.Context, from *drand.Participant, to []*drand.Participant, - action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error), + action SendAction, ) error } diff --git a/dkg/execution.go b/dkg/execution.go index d686f38b6..d7c3888f6 100644 --- a/dkg/execution.go +++ b/dkg/execution.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/drand/drand/metrics" "github.com/drand/kyber" "github.com/drand/drand/crypto" @@ -21,6 +22,9 @@ import ( ) func (d *DKGProcess) setupDKG(ctx context.Context, beaconID string) (*dkg.Config, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.setupDKG") + defer span.End() + current, err := d.store.GetCurrent(beaconID) if err != nil { return nil, err @@ -79,7 +83,10 @@ func (d *DKGProcess) setupDKG(ctx context.Context, beaconID string) (*dkg.Config // this is done rarely and is a shared object: no good reason not to use a clone (and it makes the race checker happy :)) // //nolint:gocritic -func (d *DKGProcess) executeAndFinishDKG(beaconID string, config dkg.Config) error { +func (d *DKGProcess) executeAndFinishDKG(ctx context.Context, beaconID string, config dkg.Config) error { + ctx, span := metrics.NewSpan(ctx, "dkg.executeAndFinishDKG") + defer span.End() + current, err := d.store.GetCurrent(beaconID) if err != nil { return err @@ -91,7 +98,7 @@ func (d *DKGProcess) executeAndFinishDKG(beaconID string, config dkg.Config) err } executeAndStoreDKG := func() error { - output, err := d.startDKGExecution(beaconID, current, &config) + output, err := d.startDKGExecution(ctx, beaconID, current, &config) if err != nil { return err } @@ -134,7 +141,10 @@ func (d *DKGProcess) executeAndFinishDKG(beaconID string, config dkg.Config) err return rollbackOnError(executeAndStoreDKG, leaveNetwork) } -func (d *DKGProcess) startDKGExecution(beaconID string, current *DBState, config *dkg.Config) (*ExecutionOutput, error) { +func (d *DKGProcess) startDKGExecution(ctx context.Context, beaconID string, current *DBState, config *dkg.Config) (*ExecutionOutput, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.startDKGExecution") + defer span.End() + phaser := dkg.NewTimePhaser(d.config.TimeBetweenDKGPhases) go phaser.Start() @@ -168,7 +178,7 @@ func (d *DKGProcess) startDKGExecution(beaconID string, current *DBState, config finalGroup = append(finalGroup, config.NewNodes[v.Index]) } - groupFile, err := asGroup(current, &share, finalGroup) + groupFile, err := asGroup(ctx, current, &share, finalGroup) if err != nil { return nil, err } @@ -183,7 +193,10 @@ func (d *DKGProcess) startDKGExecution(beaconID string, current *DBState, config } } -func asGroup(details *DBState, keyShare *key.Share, finalNodes []dkg.Node) (key.Group, error) { +func asGroup(ctx context.Context, details *DBState, keyShare *key.Share, finalNodes []dkg.Node) (key.Group, error) { + ctx, span := metrics.NewSpan(ctx, "dkg.asGroup") + defer span.End() + sch, found := crypto.GetSchemeByID(details.SchemeID) if !found { return key.Group{}, fmt.Errorf("the schemeID for the given group did not exist, scheme: %s", details.SchemeID) diff --git a/dkg/network.go b/dkg/network.go index 35a111600..7f31b2b57 100644 --- a/dkg/network.go +++ b/dkg/network.go @@ -1,11 +1,13 @@ package dkg import ( + "context" "fmt" "strings" "sync" "github.com/drand/drand/log" + "github.com/drand/drand/metrics" "github.com/drand/drand/net" "github.com/drand/drand/util" @@ -17,33 +19,47 @@ type GrpcNetwork struct { log log.Logger } +type SendAction func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) + // Send currently sends sequentially (boo!) // refactor this to fork join (and attempt all participants, in order that it can be used for rollbacks too) func (n *GrpcNetwork) Send( + ctx context.Context, from *drand.Participant, to []*drand.Participant, - action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error), + action SendAction, ) error { - return n.send(from, to, action, false) + ctx, span := metrics.NewSpan(ctx, "grpc.Send") + defer span.End() + + return n.send(ctx, from, to, action, false) } func (n *GrpcNetwork) SendIgnoringConnectionError( + ctx context.Context, from *drand.Participant, to []*drand.Participant, - action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error), + action SendAction, ) error { - return n.send(from, to, action, true) + ctx, span := metrics.NewSpan(ctx, "grpc.SendIgnoringConnectionError") + defer span.End() + + return n.send(ctx, from, to, action, true) } // send forks a goroutine for each recipient and sends a network request to them // in the case of error, it returns the first error // if they are all successful, it returns nil func (n *GrpcNetwork) send( + ctx context.Context, from *drand.Participant, to []*drand.Participant, - action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error), + action SendAction, ignoreConnectionErrors bool, ) error { + ctx, span := metrics.NewSpan(ctx, "grpc.send") + defer span.End() + wait := sync.WaitGroup{} errs := make(chan error, len(to)) wait.Add(len(to)) @@ -58,7 +74,7 @@ func (n *GrpcNetwork) send( go func() { defer wait.Done() - _, err := action(n.dkgClient, util.ToPeer(p)) + _, err := action(ctx, n.dkgClient, util.ToPeer(p)) if err != nil { if ignoreConnectionErrors && isConnectionError(err) { n.log.Warnw(fmt.Sprintf("connection error to node %s", p.Address), "err", err) From 3a6dd548b2aa96504f083a4ece0935c9a817fd04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Mon, 27 Mar 2023 11:03:25 +0300 Subject: [PATCH 5/9] Fix missing refactoring --- dkg/actions_active_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dkg/actions_active_test.go b/dkg/actions_active_test.go index 581e6fb90..8739a13fe 100644 --- a/dkg/actions_active_test.go +++ b/dkg/actions_active_test.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/drand/drand/net" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" @@ -504,11 +502,11 @@ type MockNetwork struct { mock.Mock } -func (n *MockNetwork) Send(from *drand.Participant, to []*drand.Participant, action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error)) error { +func (n *MockNetwork) Send(_ context.Context, from *drand.Participant, to []*drand.Participant, action SendAction) error { args := n.Called(from, to, action) return args.Error(0) } -func (n *MockNetwork) SendIgnoringConnectionError(from *drand.Participant, to []*drand.Participant, action func(client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error)) error { +func (n *MockNetwork) SendIgnoringConnectionError(_ context.Context, from *drand.Participant, to []*drand.Participant, action SendAction) error { args := n.Called(from, to, action) return args.Error(0) } From 3d286a0fb40ba1f172b03021efd4ee5e1ddf3b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Thu, 30 Mar 2023 23:20:48 +0300 Subject: [PATCH 6/9] Updates per code review comments --- chain/beacon/chainstore.go | 9 ++++----- chain/beacon/node.go | 4 ++-- docker-compose.yaml | 18 ------------------ test/metrics.go | 4 ++-- 4 files changed, 8 insertions(+), 27 deletions(-) delete mode 100644 docker-compose.yaml diff --git a/chain/beacon/chainstore.go b/chain/beacon/chainstore.go index 236343889..7c942dd62 100644 --- a/chain/beacon/chainstore.go +++ b/chain/beacon/chainstore.go @@ -110,15 +110,14 @@ func newChainStore(ctx context.Context, l log.Logger, cf *Config, cl net.Protoco cs.beaconStoredAgg <- b }) // TODO maybe look if it's worth having multiple workers there - go func() { - cs.runAggregator() - }() + go cs.runAggregator() return cs, nil } -func (c *chainStore) NewValidPartial(spanContext oteltrace.SpanContext, addr string, p *drand.PartialBeaconPacket) { +func (c *chainStore) NewValidPartial(ctx context.Context, addr string, p *drand.PartialBeaconPacket) { + spanCtx := oteltrace.SpanContextFromContext(ctx) c.newPartials <- partialInfo{ - spanContext: spanContext, + spanContext: spanCtx, addr: addr, p: p, diff --git a/chain/beacon/node.go b/chain/beacon/node.go index 7506e199c..2acd98a3e 100644 --- a/chain/beacon/node.go +++ b/chain/beacon/node.go @@ -207,7 +207,7 @@ func (h *Handler) ProcessPartialBeacon(ctx context.Context, p *proto.PartialBeac return new(proto.Empty), nil } - h.chain.NewValidPartial(span.SpanContext(), addr, p) + h.chain.NewValidPartial(ctx, addr, p) return new(proto.Empty), nil } @@ -519,7 +519,7 @@ func (h *Handler) broadcastNextPartial(ctx context.Context, current roundInfo, u Metadata: metadata, } - h.chain.NewValidPartial(span.SpanContext(), h.addr, packet) + h.chain.NewValidPartial(ctx, h.addr, packet) for _, id := range h.crypto.GetGroup().Nodes { select { case <-ctx.Done(): diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 32486e14b..000000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3.8" -services: - jaeger: - image: jaegertracing/all-in-one:1.38.1 - environment: - - COLLECTOR_ZIPKIN_HOST_PORT=:9411 - - COLLECTOR_OTLP_ENABLED=true - ports: - - 6831:6831/udp - - 6832:6832/udp - - 5778:5778 - - 16686:16686 - - 4317:4317 - - 4318:4318 - - 14250:14250 - - 14268:14268 - - 14269:14269 - - 9411:9411 diff --git a/test/metrics.go b/test/metrics.go index b288a2570..4518c1f25 100644 --- a/test/metrics.go +++ b/test/metrics.go @@ -11,7 +11,7 @@ import ( "github.com/drand/drand/metrics" ) -// Tracer ... +// Tracer allows building a tracer in the context of a test func Tracer(t *testing.T, ctx context.Context) oteltrace.Tracer { endpoint := os.Getenv("DRAND_TRACES") tracer, tracerShutdown := metrics.InitTracer(t.Name(), endpoint, 1) @@ -22,7 +22,7 @@ func Tracer(t *testing.T, ctx context.Context) oteltrace.Tracer { return tracer } -// TracerWithName adds the `_$name` suffix to the tracer name +// TracerWithName like Tracer but also adds the `_$name` suffix to the tracer name func TracerWithName(t *testing.T, ctx context.Context, name string) oteltrace.Tracer { endpoint := os.Getenv("DRAND_TRACES") tracer, tracerShutdown := metrics.InitTracer(fmt.Sprintf("%s_%s", t.Name(), name), endpoint, 1) From 088ba9efd45e8397e20db6d92f056a0c91117cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Fri, 31 Mar 2023 17:41:15 +0300 Subject: [PATCH 7/9] Updates per code review comments --- cmd/drand-cli/cli_test.go | 2 +- dkg/actions_passive.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cmd/drand-cli/cli_test.go b/cmd/drand-cli/cli_test.go index 197aa81b3..4fbb54897 100644 --- a/cmd/drand-cli/cli_test.go +++ b/cmd/drand-cli/cli_test.go @@ -461,7 +461,7 @@ func TestStartWithoutGroup(t *testing.T) { }) require.NoError(t, err) - // Have to close it afterwards or starting the node will become unrespondive + // Have to close it afterwards or starting the node will become unresponsive err = dStore.Close() require.NoError(t, err) diff --git a/dkg/actions_passive.go b/dkg/actions_passive.go index 06dc20096..37f16ef46 100644 --- a/dkg/actions_passive.go +++ b/dkg/actions_passive.go @@ -13,7 +13,7 @@ import ( // upon receiving messages from other nodes: storing proposals, aborting when the leader aborts, etc func (d *DKGProcess) Propose(ctx context.Context, proposal *drand.ProposalTerms) (*drand.EmptyResponse, error) { - _, span := metrics.NewSpan(ctx, "dkg.DKGStatus") + _, span := metrics.NewSpan(ctx, "dkg.Propose") defer span.End() err := d.executeAction("DKG proposal", proposal.BeaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { @@ -36,7 +36,10 @@ func (d *DKGProcess) Accept(ctx context.Context, acceptance *drand.AcceptProposa return responseOrError(err) } -func (d *DKGProcess) Reject(_ context.Context, rejection *drand.RejectProposal) (*drand.EmptyResponse, error) { +func (d *DKGProcess) Reject(ctx context.Context, rejection *drand.RejectProposal) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.Reject") + defer span.End() + err := d.executeAction("DKG rejection", rejection.Metadata.BeaconID, func(me *drand.Participant, current *DBState) (*DBState, error) { return current.ReceivedRejection(me, rejection.Rejector) }) @@ -93,6 +96,9 @@ func (d *DKGProcess) Execute(ctx context.Context, kickoff *drand.StartExecution) // BroadcastDKG gossips internal DKG protocol messages to other nodes (i.e. any messages encapsulated in the Kyber DKG) func (d *DKGProcess) BroadcastDKG(ctx context.Context, packet *drand.DKGPacket) (*drand.EmptyResponse, error) { + _, span := metrics.NewSpan(ctx, "dkg.BroadcastDKG") + defer span.End() + beaconID := packet.Dkg.Metadata.BeaconID d.lock.Lock() broadcaster := d.Executions[beaconID] From 885cef486fa1d2352eee1ecca0b53278e2fa0a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florin=20P=C4=83=C8=9Ban?= Date: Fri, 31 Mar 2023 17:43:36 +0300 Subject: [PATCH 8/9] Make the linter happy --- dkg/actions_active.go | 14 ++++++++------ dkg/execution.go | 6 ++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dkg/actions_active.go b/dkg/actions_active.go index 22832a8d0..8b7471ab4 100644 --- a/dkg/actions_active.go +++ b/dkg/actions_active.go @@ -68,9 +68,10 @@ func (d *DKGProcess) StartNetwork(ctx context.Context, options *drand.FirstPropo } sendProposalAndStoreNextState := func() error { - err := d.network.Send(ctx, me, nextState.Joining, func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { - return client.Propose(ctx, peer, &terms) - }) + err := d.network.Send(ctx, me, nextState.Joining, + func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + return client.Propose(ctx, peer, &terms) + }) if err != nil { return err } @@ -177,9 +178,10 @@ func (d *DKGProcess) StartProposal(ctx context.Context, options *drand.ProposalO // we make a best effort attempt to send the proposal to the leaver, but if their node is e.g. turned off then // we ignore the error if len(nextState.Leaving) > 0 { - err = d.network.Send(ctx, me, nextState.Leaving, func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { - return client.Propose(ctx, peer, &terms) - }) + err = d.network.Send(ctx, me, nextState.Leaving, + func(ctx context.Context, client net.DKGClient, peer net.Peer) (*drand.EmptyResponse, error) { + return client.Propose(ctx, peer, &terms) + }) if err != nil { d.log.Warnw("could not send proposal to a leaving participant", "err", err) diff --git a/dkg/execution.go b/dkg/execution.go index d7c3888f6..a30394c04 100644 --- a/dkg/execution.go +++ b/dkg/execution.go @@ -141,6 +141,7 @@ func (d *DKGProcess) executeAndFinishDKG(ctx context.Context, beaconID string, c return rollbackOnError(executeAndStoreDKG, leaveNetwork) } +//nolint:lll // This function has a few, explicitly named, paramteres. func (d *DKGProcess) startDKGExecution(ctx context.Context, beaconID string, current *DBState, config *dkg.Config) (*ExecutionOutput, error) { ctx, span := metrics.NewSpan(ctx, "dkg.startDKGExecution") defer span.End() @@ -193,10 +194,7 @@ func (d *DKGProcess) startDKGExecution(ctx context.Context, beaconID string, cur } } -func asGroup(ctx context.Context, details *DBState, keyShare *key.Share, finalNodes []dkg.Node) (key.Group, error) { - ctx, span := metrics.NewSpan(ctx, "dkg.asGroup") - defer span.End() - +func asGroup(_ context.Context, details *DBState, keyShare *key.Share, finalNodes []dkg.Node) (key.Group, error) { sch, found := crypto.GetSchemeByID(details.SchemeID) if !found { return key.Group{}, fmt.Errorf("the schemeID for the given group did not exist, scheme: %s", details.SchemeID) From 65e8b3175596002da1ef806655796186b402a789 Mon Sep 17 00:00:00 2001 From: Patrick McClurg Date: Wed, 12 Apr 2023 15:38:02 +0200 Subject: [PATCH 9/9] added contexts to migrate command --- core/drand_daemon_control.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/drand_daemon_control.go b/core/drand_daemon_control.go index 265cfa804..c04662bd5 100644 --- a/core/drand_daemon_control.go +++ b/core/drand_daemon_control.go @@ -275,7 +275,7 @@ func (dd *DrandDaemon) WaitExit() chan bool { return dd.exitCh } -func (dd *DrandDaemon) Migrate(context.Context, *drand.Empty) (*drand.Empty, error) { +func (dd *DrandDaemon) Migrate(context context.Context, _ *drand.Empty) (*drand.Empty, error) { for beaconID, bp := range dd.beaconProcesses { dd.log.Debugw("Migrating DKG from group file...", "beaconID", beaconID) @@ -296,8 +296,8 @@ func (dd *DrandDaemon) Migrate(context.Context, *drand.Empty) (*drand.Empty, err // then stop and start the beacon process to load the new DKG // state and start listening for messages correctly - bp.StopBeacon() - _, err = dd.LoadBeaconFromStore(beaconID, bp.store) + bp.StopBeacon(context) + _, err = dd.LoadBeaconFromStore(context, beaconID, bp.store) if err != nil { return nil, err }