From af3d370eaea7aff2fa339b5601b981e52a10276b Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Sun, 13 Aug 2023 18:32:10 +0200 Subject: [PATCH 01/28] wip --- client/aggregator.go | 220 ++++ client/aggregator_test.go | 84 ++ client/cache.go | 120 +++ client/cache_test.go | 136 +++ client/client.go | 347 ++++++ client/client_test.go | 432 ++++++++ client/doc.go | 70 ++ client/empty.go | 48 + client/empty_test.go | 69 ++ client/grpc/client.go | 148 +++ client/grpc/client_test.go | 114 ++ client/grpc/doc.go | 43 + client/http/doc.go | 45 + client/http/http.go | 401 +++++++ client/http/http_test.go | 301 ++++++ client/http/metric.go | 67 ++ client/lp2p/client.go | 254 +++++ client/lp2p/client_test.go | 246 +++++ client/lp2p/doc.go | 97 ++ client/lp2p/validator.go | 90 ++ client/lp2p/validator_test.go | 271 +++++ client/metric.go | 53 + client/metric_test.go | 32 + client/mock/mock.go | 152 +++ client/optimizing.go | 642 +++++++++++ client/optimizing_test.go | 317 ++++++ client/poll.go | 64 ++ client/random.go | 25 + client/test/cache/cache.go | 36 + client/test/http/mock/httpserver.go | 71 ++ client/test/result/mock/result.go | 128 +++ client/utils_test.go | 65 ++ client/verify.go | 206 ++++ client/verify_test.go | 61 ++ client/watcher.go | 35 + client/watcher_test.go | 86 ++ cmd/Dockerfile | 71 ++ cmd/entrypoint.sh | 27 + cmd/main.go | 209 ++++ internal/cli.go | 1316 +++++++++++++++++++++++ internal/cli_test.go | 1520 +++++++++++++++++++++++++++ internal/control.go | 535 ++++++++++ internal/daemon.go | 80 ++ internal/dkg_cli.go | 789 ++++++++++++++ internal/dkg_cli_test.go | 66 ++ internal/lib/cli_test.go | 170 +++ internal/proposal_file.go | 124 +++ internal/proposal_file_test.go | 70 ++ internal/public.go | 116 ++ main.go | 16 + 50 files changed, 10685 insertions(+) create mode 100644 client/aggregator.go create mode 100644 client/aggregator_test.go create mode 100644 client/cache.go create mode 100644 client/cache_test.go create mode 100644 client/client.go create mode 100644 client/client_test.go create mode 100644 client/doc.go create mode 100644 client/empty.go create mode 100644 client/empty_test.go create mode 100644 client/grpc/client.go create mode 100644 client/grpc/client_test.go create mode 100644 client/grpc/doc.go create mode 100644 client/http/doc.go create mode 100644 client/http/http.go create mode 100644 client/http/http_test.go create mode 100644 client/http/metric.go create mode 100644 client/lp2p/client.go create mode 100644 client/lp2p/client_test.go create mode 100644 client/lp2p/doc.go create mode 100644 client/lp2p/validator.go create mode 100644 client/lp2p/validator_test.go create mode 100644 client/metric.go create mode 100644 client/metric_test.go create mode 100644 client/mock/mock.go create mode 100644 client/optimizing.go create mode 100644 client/optimizing_test.go create mode 100644 client/poll.go create mode 100644 client/random.go create mode 100644 client/test/cache/cache.go create mode 100644 client/test/http/mock/httpserver.go create mode 100644 client/test/result/mock/result.go create mode 100644 client/utils_test.go create mode 100644 client/verify.go create mode 100644 client/verify_test.go create mode 100644 client/watcher.go create mode 100644 client/watcher_test.go create mode 100644 cmd/Dockerfile create mode 100644 cmd/entrypoint.sh create mode 100644 cmd/main.go create mode 100644 internal/cli.go create mode 100644 internal/cli_test.go create mode 100644 internal/control.go create mode 100644 internal/daemon.go create mode 100644 internal/dkg_cli.go create mode 100644 internal/dkg_cli_test.go create mode 100644 internal/lib/cli_test.go create mode 100644 internal/proposal_file.go create mode 100644 internal/proposal_file_test.go create mode 100644 internal/public.go create mode 100644 main.go diff --git a/client/aggregator.go b/client/aggregator.go new file mode 100644 index 0000000..61714c8 --- /dev/null +++ b/client/aggregator.go @@ -0,0 +1,220 @@ +package client + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" +) + +const ( + aggregatorWatchBuffer = 5 + // defaultAutoWatchRetry is the time after which the watch channel + // created by the autoWatch is re-opened when no context error occurred. + defaultAutoWatchRetry = time.Second * 30 +) + +// newWatchAggregator maintains state of consumers calling `Watch` so that a +// single `watch` request is made to the underlying client. +// There are 3 modes taken by this aggregator. If autowatch is set, a single `watch` +// will always be invoked on the provided client. If it is not set, but a `watch client`(wc) +// is passed, a `watch` will be run on the watch client in the absence of external watchers, +// which will swap watching over to the main client. If no watch client is set and autowatch is off +// then a single watch will only run when an external watch is requested. +func newWatchAggregator(l log.Logger, c, wc client.Client, autoWatch bool, autoWatchRetry time.Duration) *watchAggregator { + if autoWatchRetry == 0 { + autoWatchRetry = defaultAutoWatchRetry + } + aggregator := &watchAggregator{ + Client: c, + passiveClient: wc, + autoWatch: autoWatch, + autoWatchRetry: autoWatchRetry, + log: l, + subscribers: make([]subscriber, 0), + } + return aggregator +} + +type subscriber struct { + ctx context.Context + c chan client.Result +} + +type watchAggregator struct { + client.Client + passiveClient client.Client + autoWatch bool + autoWatchRetry time.Duration + log log.Logger + cancelAutoWatch context.CancelFunc + + subscriberLock sync.Mutex + subscribers []subscriber + cancelPassive context.CancelFunc +} + +// Start initiates auto watching if configured to do so. +// SetLog should not be called after Start. +func (c *watchAggregator) Start() { + if c.autoWatch { + c.startAutoWatch(true) + } else if c.passiveClient != nil { + c.startAutoWatch(false) + } +} + +// SetLog configures the client log output +func (c *watchAggregator) SetLog(l log.Logger) { + c.log = l +} + +// String returns the name of this client. +func (c *watchAggregator) String() string { + return fmt.Sprintf("%s.(+aggregator)", c.Client) +} + +func (c *watchAggregator) startAutoWatch(full bool) { + ctx, cancel := context.WithCancel(context.Background()) + c.cancelAutoWatch = cancel + go func() { + for { + var results <-chan client.Result + if full { + results = c.Watch(ctx) + } else if c.passiveClient != nil { + results = c.passiveWatch(ctx) + } + LOOP: + for { + select { + case _, ok := <-results: + if !ok { + c.log.Infow("", "watch_aggregator", "auto watch ended") + break LOOP + } + case <-ctx.Done(): + return + } + } + if c.autoWatchRetry < 0 { + return + } + t := time.NewTimer(c.autoWatchRetry) + select { + case <-t.C: + case <-ctx.Done(): + if !t.Stop() { + <-t.C + } + } + c.log.Infow("", "watch_aggregator", "retrying auto watch") + } + }() +} + +// passiveWatch is a degraded form of watch, where watch only hits the 'passive client' +// unless distribution is actually needed. +func (c *watchAggregator) passiveWatch(ctx context.Context) <-chan client.Result { + c.subscriberLock.Lock() + defer c.subscriberLock.Unlock() + + if c.cancelPassive != nil { + c.log.Warnw("", "watch_aggregator", "only support one passive watch") + return nil + } + + wc := make(chan client.Result) + if len(c.subscribers) == 0 { + ctx, cancel := context.WithCancel(ctx) + c.cancelPassive = cancel + go c.sink(c.passiveClient.Watch(ctx), wc) + } else { + // trigger the startAutowatch to retry on backoff + close(wc) + } + return wc +} + +func (c *watchAggregator) Watch(ctx context.Context) <-chan client.Result { + c.subscriberLock.Lock() + defer c.subscriberLock.Unlock() + + sub := subscriber{ctx, make(chan client.Result, aggregatorWatchBuffer)} + c.subscribers = append(c.subscribers, sub) + + if len(c.subscribers) == 1 { + if c.cancelPassive != nil { + c.cancelPassive() + c.cancelPassive = nil + } + // TODO: any reason we are not passing the existing context here? + ctx, cancel := context.WithCancel(context.Background()) + go c.distribute(c.Client.Watch(ctx), cancel) + } + return sub.c +} + +func (c *watchAggregator) sink(in <-chan client.Result, out chan client.Result) { + defer close(out) + for range in { + continue + } +} + +func (c *watchAggregator) distribute(in <-chan client.Result, cancel context.CancelFunc) { + defer cancel() + for { + c.subscriberLock.Lock() + if len(c.subscribers) == 0 { + c.subscriberLock.Unlock() + c.log.Warnw("", "watch_aggregator", "no subscribers to distribute results to") + return + } + aCtx := c.subscribers[0].ctx + c.subscriberLock.Unlock() + + var m client.Result + var ok bool + + select { + case m, ok = <-in: + case <-aCtx.Done(): + } + + c.subscriberLock.Lock() + curr := c.subscribers + c.subscribers = c.subscribers[:0] + + for _, s := range curr { + if ok && s.ctx.Err() == nil { + c.subscribers = append(c.subscribers, s) + if m != nil { + select { + case s.c <- m: + default: + c.log.Warnw("", "watch_aggregator", "dropped watch message to subscriber. full channel") + } + } + } else { + close(s.c) + } + } + c.subscriberLock.Unlock() + + if !ok { + return + } + } +} + +func (c *watchAggregator) Close() error { + err := c.Client.Close() + if c.cancelAutoWatch != nil { + c.cancelAutoWatch() + } + return err +} diff --git a/client/aggregator_test.go b/client/aggregator_test.go new file mode 100644 index 0000000..1509ab2 --- /dev/null +++ b/client/aggregator_test.go @@ -0,0 +1,84 @@ +package client + +import ( + "sync" + "testing" + "time" + + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestAggregatorClose(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(1) + + c := &clientMock.Client{ + WatchCh: make(chan client.Result), + CloseF: func() error { + wg.Done() + return nil + }, + } + + ac := newWatchAggregator(testlogger.New(t), c, nil, true, 0) + + err := ac.Close() // should cancel the autoWatch and close the underlying client + if err != nil { + t.Fatal(err) + } + + wg.Wait() // wait for underlying client to close +} + +func TestAggregatorPassive(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(1) + + c := &clientMock.Client{ + WatchCh: make(chan client.Result, 1), + CloseF: func() error { + wg.Done() + return nil + }, + } + + wc := &clientMock.Client{ + WatchCh: make(chan client.Result, 1), + CloseF: func() error { + return nil + }, + } + + ac := newWatchAggregator(testlogger.New(t), c, wc, false, 0) + + wc.WatchCh <- &mock.Result{Rnd: 1234} + c.WatchCh <- &mock.Result{Rnd: 5678} + + ac.Start() + + time.Sleep(50 * time.Millisecond) + + zzz := time.NewTimer(time.Millisecond * 50) + select { + case w := <-wc.WatchCh: + t.Fatalf("passive watch should be drained, but got %v", w) + case <-zzz.C: + } + + zzz = time.NewTimer(time.Millisecond * 50) + select { + case <-c.WatchCh: + case <-zzz.C: + t.Fatalf("active watch should not have been called but was") + } + + err := ac.Close() + if err != nil { + t.Fatal(err) + } + + wg.Wait() +} diff --git a/client/cache.go b/client/cache.go new file mode 100644 index 0000000..d153541 --- /dev/null +++ b/client/cache.go @@ -0,0 +1,120 @@ +package client + +import ( + "context" + "fmt" + + lru "github.com/hashicorp/golang-lru" + + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" +) + +// Cache provides a mechanism to check for rounds in the cache. +type Cache interface { + // TryGet provides a round beacon or nil if it is not cached. + TryGet(round uint64) client.Result + // Add adds an item to the cache + Add(uint64, client.Result) +} + +// makeCache creates a cache of a given size +func makeCache(size int) (Cache, error) { + if size == 0 { + return &nilCache{}, nil + } + c, err := lru.NewARC(size) + if err != nil { + return nil, err + } + return &typedCache{c}, nil +} + +// typedCache wraps an ARCCache containing beacon results. +type typedCache struct { + *lru.ARCCache +} + +// Add a result to the cache +func (t *typedCache) Add(round uint64, result client.Result) { + t.ARCCache.Add(round, result) +} + +// TryGet attempts to get a result from the cache +func (t *typedCache) TryGet(round uint64) client.Result { + if val, ok := t.ARCCache.Get(round); ok { + return val.(client.Result) + } + return nil +} + +// nilCache implements a cache with size 0 +type nilCache struct{} + +// Add a result to the cache +func (*nilCache) Add(_ uint64, _ client.Result) { +} + +// TryGet attempts to get ar esult from the cache +func (*nilCache) TryGet(_ uint64) client.Result { + return nil +} + +// NewCachingClient is a meta client that stores an LRU cache of +// recently fetched random values. +func NewCachingClient(l log.Logger, c client.Client, cache Cache) (client.Client, error) { + return &cachingClient{ + Client: c, + cache: cache, + log: l, + }, nil +} + +type cachingClient struct { + client.Client + + cache Cache + log log.Logger +} + +// SetLog configures the client log output +func (c *cachingClient) SetLog(l log.Logger) { + c.log = l +} + +// String returns the name of this client. +func (c *cachingClient) String() string { + if arc, ok := c.cache.(*typedCache); ok { + return fmt.Sprintf("%s.(+%d el cache)", c.Client, arc.ARCCache.Len()) + } + return fmt.Sprintf("%s.(+nil cache)", c.Client) +} + +// Get returns the randomness at `round` or an error. +func (c *cachingClient) Get(ctx context.Context, round uint64) (res client.Result, err error) { + if val := c.cache.TryGet(round); val != nil { + return val, nil + } + val, err := c.Client.Get(ctx, round) + if err == nil && val != nil { + c.cache.Add(val.Round(), val) + } + return val, err +} + +func (c *cachingClient) Watch(ctx context.Context) <-chan client.Result { + in := c.Client.Watch(ctx) + out := make(chan client.Result) + go func() { + for result := range in { + c.cache.Add(result.Round(), result) + out <- result + } + close(out) + }() + return out +} + +func (c *cachingClient) Close() error { + return c.Client.Close() +} diff --git a/client/cache_test.go b/client/cache_test.go new file mode 100644 index 0000000..ebf3f38 --- /dev/null +++ b/client/cache_test.go @@ -0,0 +1,136 @@ +package client + +import ( + "context" + "sync" + "testing" + + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestCacheGet(t *testing.T) { + m := clientMock.ClientWithResults(1, 6) + cache, err := makeCache(3) + if err != nil { + t.Fatal(err) + } + c, err := NewCachingClient(testlogger.New(t), m, cache) + if err != nil { + t.Fatal(err) + } + res, e := c.Get(context.Background(), 1) + if e != nil { + t.Fatal(e) + } + res.(*mock.Result).AssertValid(t) + + _, e = c.Get(context.Background(), 1) + if e != nil { + t.Fatal(e) + } + if len(m.Results) < 4 { + t.Fatal("multiple gets should cache.") + } + _, e = c.Get(context.Background(), 2) + if e != nil { + t.Fatal(e) + } + _, e = c.Get(context.Background(), 3) + if e != nil { + t.Fatal(e) + } + + _, e = c.Get(context.Background(), 1) + if e != nil { + t.Fatal(e) + } + if len(m.Results) != 2 { + t.Fatalf("unexpected cache size. %d", len(m.Results)) + } +} + +func TestCacheGetLatest(t *testing.T) { + m := clientMock.ClientWithResults(1, 3) + cache, err := makeCache(3) + if err != nil { + t.Fatal(err) + } + c, err := NewCachingClient(testlogger.New(t), m, cache) + if err != nil { + t.Fatal(err) + } + + r0, e := c.Get(context.Background(), 0) + if e != nil { + t.Fatal(e) + } + r1, e := c.Get(context.Background(), 0) + if e != nil { + t.Fatal(e) + } + + if r0.Round() == r1.Round() { + t.Fatal("cached result for latest") + } +} + +func TestCacheWatch(t *testing.T) { + m := clientMock.ClientWithResults(2, 6) + rc := make(chan client.Result, 1) + m.WatchCh = rc + arcCache, err := makeCache(3) + if err != nil { + t.Fatal(err) + } + lg := testlogger.New(t) + cache, _ := NewCachingClient(lg, m, arcCache) + c := newWatchAggregator(lg, cache, nil, false, 0) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + r1 := c.Watch(ctx) + rc <- &mock.Result{Rnd: 1, Rand: []byte{1}} + _, ok := <-r1 + if !ok { + t.Fatal("results should propagate") + } + + _, err = c.Get(context.Background(), 1) + if err != nil { + t.Fatal(err) + } + if len(m.Results) != 4 { + t.Fatalf("getting should be served by cache.") + } +} + +func TestCacheClose(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(1) + + c := &clientMock.Client{ + WatchCh: make(chan client.Result), + CloseF: func() error { + wg.Done() + return nil + }, + } + + cache, err := makeCache(1) + if err != nil { + t.Fatal(err) + } + ca, err := NewCachingClient(testlogger.New(t), c, cache) + if err != nil { + t.Fatal(err) + } + + err = ca.Close() // should close the underlying client + if err != nil { + t.Fatal(err) + } + + wg.Wait() // wait for underlying client to close +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000..10cc998 --- /dev/null +++ b/client/client.go @@ -0,0 +1,347 @@ +package client + +import ( + "bytes" + "context" + "errors" + "fmt" + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/metrics" +) + +const clientStartupTimeoutDefault = time.Second * 5 + +// New creates a client with specified configuration. +func New(ctx context.Context, l log.Logger, options ...Option) (client.Client, error) { + cfg := clientConfig{ + cacheSize: 32, + log: l, + } + + for _, opt := range options { + if err := opt(&cfg); err != nil { + return nil, err + } + } + return makeClient(ctx, l, &cfg) +} + +// Wrap provides a single entrypoint for wrapping a concrete client +// implementation with configured aggregation, caching, and retry logic +func Wrap(ctx context.Context, l log.Logger, clients []client.Client, options ...Option) (client.Client, error) { + return New(ctx, l, append(options, From(clients...))...) +} + +func trySetLog(c client.Client, l log.Logger) { + if lc, ok := c.(client.LoggingClient); ok { + lc.SetLog(l) + } +} + +// makeClient creates a client from a configuration. +func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Client, error) { + if !cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { + return nil, errors.New("no root of trust specified") + } + if len(cfg.clients) == 0 && cfg.watcher == nil { + return nil, errors.New("no points of contact specified") + } + + var err error + + // provision cache + cache, err := makeCache(cfg.cacheSize) + if err != nil { + return nil, err + } + + // try to populate chain info + if err := cfg.tryPopulateInfo(ctx, cfg.clients...); err != nil { + return nil, err + } + + // provision watcher client + var wc client.Client + if cfg.watcher != nil { + wc, err = makeWatcherClient(cfg, cache) + if err != nil { + return nil, err + } + cfg.clients = append(cfg.clients, wc) + } + + for _, c := range cfg.clients { + trySetLog(c, cfg.log) + } + + var c client.Client + + verifiers := make([]client.Client, 0, len(cfg.clients)) + for _, source := range cfg.clients { + sch, err := crypto.GetSchemeByIDWithDefault(cfg.chainInfo.Scheme) + if err != nil { + return nil, fmt.Errorf("invalid scheme name in makeClient: %w", err) + } + + nv := newVerifyingClient(source, cfg.previousResult, cfg.fullVerify, sch) + verifiers = append(verifiers, nv) + if source == wc { + wc = nv + } + } + + c, err = makeOptimizingClient(l, cfg, verifiers, wc, cache) + if err != nil { + return nil, err + } + + wa := newWatchAggregator(l, c, wc, cfg.autoWatch, cfg.autoWatchRetry) + c = wa + trySetLog(c, cfg.log) + + wa.Start() + + return attachMetrics(cfg, c) +} + +//nolint:lll // This function has nicely named parameters, so it's long. +func makeOptimizingClient(l log.Logger, cfg *clientConfig, verifiers []client.Client, watcher client.Client, cache Cache) (client.Client, error) { + oc, err := newOptimizingClient(l, verifiers, 0, 0, 0, 0) + if err != nil { + return nil, err + } + if watcher != nil { + oc.MarkPassive(watcher) + } + c := client.Client(oc) + trySetLog(c, cfg.log) + + if cfg.cacheSize > 0 { + c, err = NewCachingClient(l, c, cache) + if err != nil { + return nil, err + } + trySetLog(c, cfg.log) + } + for _, v := range verifiers { + trySetLog(v, cfg.log) + v.(*verifyingClient).indirectClient = c + } + + oc.Start() + return c, nil +} + +func makeWatcherClient(cfg *clientConfig, cache Cache) (client.Client, error) { + if cfg.chainInfo == nil { + return nil, fmt.Errorf("chain info cannot be nil") + } + + w, err := cfg.watcher(cfg.chainInfo, cache) + if err != nil { + return nil, err + } + ec := EmptyClientWithInfo(cfg.chainInfo) + return &watcherClient{ec, w}, nil +} + +func attachMetrics(cfg *clientConfig, c client.Client) (client.Client, error) { + if cfg.prometheus != nil { + if err := metrics.RegisterClientMetrics(cfg.prometheus); err != nil { + return nil, err + } + return newWatchLatencyMetricClient(c, cfg.chainInfo), nil + } + return c, nil +} + +type clientConfig struct { + // clients is the set of options for fetching randomness + clients []client.Client + // watcher is a constructor function for generating a new partial client of randomness + watcher WatcherCtor + // from `chainInfo.Hash()` - serves as a root of trust for a given + // randomness chain. + chainHash []byte + // Full chain information - serves as a root of trust. + chainInfo *chain.Info + // A previously fetched result serving as a verification checkpoint if one exists. + previousResult client.Result + // chain signature verification back to the 1st round, or to a know result to ensure + // determinism in the event of a compromised chain. + fullVerify bool + // insecure indicates the root of trust does not need to be present. + insecure bool + // autoWatch causes the client to start watching immediately in the background so that new randomness + // is proactively fetched and added to the cache. + autoWatch bool + // cache size - how large of a cache to keep locally. + cacheSize int + // customized client log. + log log.Logger + + // autoWatchRetry specifies the time after which the watch channel + // created by the autoWatch is re-opened when no context error occurred. + autoWatchRetry time.Duration + // prometheus is an interface to a Prometheus system + prometheus prometheus.Registerer +} + +func (c *clientConfig) tryPopulateInfo(ctx context.Context, clients ...client.Client) (err error) { + if c.chainInfo == nil { + ctx, cancel := context.WithTimeout(ctx, clientStartupTimeoutDefault) + defer cancel() + for _, cli := range clients { + c.chainInfo, err = cli.Info(ctx) + if err == nil { + return + } + + if ctx.Err() != nil { + return ctx.Err() + } + } + } + return +} + +// Option is an option configuring a client. +type Option func(cfg *clientConfig) error + +// From constructs the client from a set of clients providing randomness +func From(c ...client.Client) Option { + return func(cfg *clientConfig) error { + cfg.clients = c + return nil + } +} + +// Insecurely indicates the client should be allowed to provide randomness +// when the root of trust is not fully provided in a validate-able way. +func Insecurely() Option { + return func(cfg *clientConfig) error { + cfg.insecure = true + return nil + } +} + +// WithCacheSize specifies how large of a cache of randomness values should be +// kept locally. Default 32 +func WithCacheSize(size int) Option { + return func(cfg *clientConfig) error { + cfg.cacheSize = size + return nil + } +} + +// WithLogger overrides the logging options for the client, +// allowing specification of additional tags, or redirection / configuration +// of logging level and output. +func WithLogger(l log.Logger) Option { + return func(cfg *clientConfig) error { + cfg.log = l + return nil + } +} + +// WithChainHash configures the client to root trust with a given randomness +// chain hash, the chain parameters will be fetched from an HTTP endpoint. +func WithChainHash(chainHash []byte) Option { + return func(cfg *clientConfig) error { + if cfg.chainInfo != nil && !bytes.Equal(cfg.chainInfo.Hash(), chainHash) { + return errors.New("refusing to override group with non-matching hash") + } + cfg.chainHash = chainHash + return nil + } +} + +// WithChainInfo configures the client to root trust in the given randomness +// chain information +func WithChainInfo(chainInfo *chain.Info) Option { + return func(cfg *clientConfig) error { + if cfg.chainHash != nil && !bytes.Equal(cfg.chainHash, chainInfo.Hash()) { + return errors.New("refusing to override hash with non-matching group") + } + cfg.chainInfo = chainInfo + return nil + } +} + +// WithVerifiedResult provides a checkpoint of randomness verified at a given round. +// Used in combination with `VerifyFullChain`, this allows for catching up only on +// previously not-yet-verified results. +func WithVerifiedResult(result client.Result) Option { + return func(cfg *clientConfig) error { + if cfg.previousResult != nil && cfg.previousResult.Round() > result.Round() { + return errors.New("refusing to override verified result with an earlier result") + } + cfg.previousResult = result + return nil + } +} + +// WithFullChainVerification validates random beacons not just as being generated correctly +// from the group signature, but ensures that the full chain is deterministic by making sure +// each round is derived correctly from the previous one. In cases of compromise where +// a single party learns sufficient shares to derive the full key, malicious randomness +// could otherwise be generated that is signed, but not properly derived from previous rounds +// according to protocol. +func WithFullChainVerification() Option { + return func(cfg *clientConfig) error { + cfg.fullVerify = true + return nil + } +} + +// Watcher supplies the `Watch` portion of the drand client interface. +type Watcher interface { + Watch(ctx context.Context) <-chan client.Result +} + +// WatcherCtor creates a Watcher once chain info is known. +type WatcherCtor func(chainInfo *chain.Info, cache Cache) (Watcher, error) + +// WithWatcher specifies a channel that can provide notifications of new +// randomness bootstrappeed from the chain info. +func WithWatcher(wc WatcherCtor) Option { + return func(cfg *clientConfig) error { + cfg.watcher = wc + return nil + } +} + +// WithAutoWatch causes the client to automatically attempt to get +// randomness for rounds, so that it will hopefully already be cached +// when `Get` is called. +func WithAutoWatch() Option { + return func(cfg *clientConfig) error { + cfg.autoWatch = true + return nil + } +} + +// WithAutoWatchRetry specifies the time after which the watch channel +// created by the autoWatch is re-opened when no context error occurred. +// Set to a negative value to disable retrying auto watch. +func WithAutoWatchRetry(interval time.Duration) Option { + return func(cfg *clientConfig) error { + cfg.autoWatchRetry = interval + return nil + } +} + +// WithPrometheus specifies a registry into which to report metrics +func WithPrometheus(r prometheus.Registerer) Option { + return func(cfg *clientConfig) error { + cfg.prometheus = r + return nil + } +} diff --git a/client/client_test.go b/client/client_test.go new file mode 100644 index 0000000..4c4fe3d --- /dev/null +++ b/client/client_test.go @@ -0,0 +1,432 @@ +package client_test + +import ( + "context" + "errors" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + + client2 "github.com/drand/drand/client" + "github.com/drand/drand/client/http" + clientMock "github.com/drand/drand/client/mock" + httpmock "github.com/drand/drand/client/test/http/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestClientConstraints(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + if _, e := client2.New(ctx, lg); e == nil { + t.Fatal("client can't be created without root of trust") + } + + if _, e := client2.New(ctx, lg, client2.WithChainHash([]byte{0})); e == nil { + t.Fatal("Client needs URLs if only a chain hash is specified") + } + + if _, e := client2.New(ctx, lg, client2.From(clientMock.ClientWithResults(0, 5))); e == nil { + t.Fatal("Client needs root of trust unless insecure specified explicitly") + } + + c := clientMock.ClientWithResults(0, 5) + // As we will run is insecurely, we will set chain info so client can fetch it + c.OptionalInfo = fakeChainInfo(t) + + if _, e := client2.New(ctx, lg, client2.From(c), client2.Insecurely()); e != nil { + t.Fatal(e) + } +} + +func TestClientMultiple(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + addr2, _, cancel2, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel2() + + httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1, "http://" + addr2}, chainInfo.Hash()) + if len(httpClients) == 0 { + t.Error("http clients is empty") + return + } + + var c client.Client + var e error + c, e = client2.New(ctx, + lg, + client2.From(httpClients...), + client2.WithChainHash(chainInfo.Hash())) + + if e != nil { + t.Fatal(e) + } + r, e := c.Get(ctx, 0) + if e != nil { + t.Fatal(e) + } + if r.Round() <= 0 { + t.Fatal("expected valid client") + } + _ = c.Close() +} + +func TestClientWithChainInfo(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + ctx := context.Background() + id := test.GenerateIDs(1)[0] + chainInfo := &chain.Info{ + PublicKey: id.Public.Key, + GenesisTime: 100, + Period: time.Second, + Scheme: crypto.DefaultSchemeID, + } + lg := testlogger.New(t) + hc, err := http.NewWithInfo(lg, "http://nxdomain.local/", chainInfo, nil) + require.NoError(t, err) + c, err := client2.New(ctx, lg, client2.WithChainInfo(chainInfo), + client2.From(hc)) + if err != nil { + t.Fatal("existing group creation shouldn't do additional validaiton.") + } + _, err = c.Get(ctx, 0) + if err == nil { + t.Fatal("bad urls should clearly not provide randomness.") + } + _ = c.Close() +} + +func TestClientCache(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + lg := testlogger.New(t) + httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) + if len(httpClients) == 0 { + t.Error("http clients is empty") + return + } + + var c client.Client + var e error + c, e = client2.New(ctx, lg, client2.From(httpClients...), + client2.WithChainHash(chainInfo.Hash()), client2.WithCacheSize(1)) + + if e != nil { + t.Fatal(e) + } + r0, e := c.Get(ctx, 0) + if e != nil { + t.Fatal(e) + } + cancel() + _, e = c.Get(ctx, r0.Round()) + if e != nil { + t.Fatal(e) + } + + _, e = c.Get(ctx, 4) + if e == nil { + t.Fatal("non-cached results should fail.") + } + _ = c.Close() +} + +func TestClientWithoutCache(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + lg := testlogger.New(t) + httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) + if len(httpClients) == 0 { + t.Error("http clients is empty") + return + } + + var c client.Client + var e error + c, e = client2.New(ctx, + lg, + client2.From(httpClients...), + client2.WithChainHash(chainInfo.Hash()), + client2.WithCacheSize(0)) + + if e != nil { + t.Fatal(e) + } + _, e = c.Get(ctx, 0) + if e != nil { + t.Fatal(e) + } + cancel() + _, e = c.Get(ctx, 0) + if e == nil { + t.Fatal("cache should be disabled.") + } + _ = c.Close() +} + +func TestClientWithWatcher(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + info, results := mock.VerifiableResults(2, sch) + + ch := make(chan client.Result, len(results)) + for i := range results { + ch <- &results[i] + } + close(ch) + + watcherCtor := func(chainInfo *chain.Info, _ client2.Cache) (client2.Watcher, error) { + return &clientMock.Client{WatchCh: ch}, nil + } + + var c client.Client + c, err = client2.New(ctx, + lg, + client2.WithChainInfo(info), + client2.WithWatcher(watcherCtor), + ) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + w := c.Watch(ctx) + + for i := 0; i < len(results); i++ { + r := <-w + compareResults(t, &results[i], r) + } + require.NoError(t, c.Close()) +} + +func TestClientWithWatcherCtorError(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + watcherErr := errors.New("boom") + watcherCtor := func(chainInfo *chain.Info, _ client2.Cache) (client2.Watcher, error) { + return nil, watcherErr + } + + // constructor should return error returned by watcherCtor + _, err := client2.New(ctx, + lg, + client2.WithChainInfo(fakeChainInfo(t)), + client2.WithWatcher(watcherCtor), + ) + if !errors.Is(err, watcherErr) { + t.Fatal(err) + } +} + +func TestClientChainHashOverrideError(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + chainInfo := fakeChainInfo(t) + _, err := client2.Wrap( + ctx, + lg, + []client.Client{client2.EmptyClientWithInfo(chainInfo)}, + client2.WithChainInfo(chainInfo), + client2.WithChainHash(fakeChainInfo(t).Hash()), + ) + if err == nil { + t.Fatal("expected error, received no error") + } + if err.Error() != "refusing to override group with non-matching hash" { + t.Fatal(err) + } +} + +func TestClientChainInfoOverrideError(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + chainInfo := fakeChainInfo(t) + _, err := client2.Wrap( + ctx, + lg, + []client.Client{client2.EmptyClientWithInfo(chainInfo)}, + client2.WithChainHash(chainInfo.Hash()), + client2.WithChainInfo(fakeChainInfo(t)), + ) + if err == nil { + t.Fatal("expected error, received no error") + } + if err.Error() != "refusing to override hash with non-matching group" { + t.Fatal(err) + } +} + +func TestClientAutoWatch(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + httpClient := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) + if len(httpClient) == 0 { + t.Error("http clients is empty") + return + } + + r1, _ := httpClient[0].Get(ctx, 1) + r2, _ := httpClient[0].Get(ctx, 2) + results := []client.Result{r1, r2} + + ch := make(chan client.Result, len(results)) + for i := range results { + ch <- results[i] + } + close(ch) + + watcherCtor := func(chainInfo *chain.Info, _ client2.Cache) (client2.Watcher, error) { + return &clientMock.Client{WatchCh: ch}, nil + } + + var c client.Client + c, err = client2.New(ctx, + lg, + client2.From(clientMock.ClientWithInfo(chainInfo)), + client2.WithChainHash(chainInfo.Hash()), + client2.WithWatcher(watcherCtor), + client2.WithAutoWatch(), + ) + + if err != nil { + t.Fatal(err) + } + + time.Sleep(chainInfo.Period) + cancel() + r, err := c.Get(ctx, results[0].Round()) + if err != nil { + t.Fatal(err) + } + compareResults(t, r, results[0]) + _ = c.Close() +} + +func TestClientAutoWatchRetry(t *testing.T) { + ctx := context.Background() + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + + info, results := mock.VerifiableResults(5, sch) + resC := make(chan client.Result) + defer close(resC) + + // done is closed after all resuls have been written to resC + done := make(chan struct{}) + + // Returns a channel that yields the verifiable results above + watchF := func(ctx context.Context) <-chan client.Result { + go func() { + for i := 0; i < len(results); i++ { + select { + case resC <- &results[i]: + case <-ctx.Done(): + return + } + } + <-time.After(time.Second) + close(done) + }() + return resC + } + + var failer clientMock.Client + failer = clientMock.Client{ + WatchF: func(ctx context.Context) <-chan client.Result { + // First call returns a closed channel + ch := make(chan client.Result) + close(ch) + // Second call returns a channel that writes results + failer.WatchF = watchF + return ch + }, + } + + var c client.Client + c, err = client2.New(ctx, + lg, + client2.From(&failer, clientMock.ClientWithInfo(info)), + client2.WithChainInfo(info), + client2.WithAutoWatch(), + client2.WithAutoWatchRetry(time.Second), + client2.WithCacheSize(len(results)), + ) + + if err != nil { + t.Fatal(err) + } + defer c.Close() + + // Wait for all the results to be consumed by the autoWatch + select { + case <-done: + case <-time.After(time.Minute): + t.Fatal("timed out waiting for results to be consumed") + } + + // We should be able to retrieve all the results from the cache. + for i := range results { + r, err := c.Get(ctx, results[i].Round()) + if err != nil { + t.Fatal(err) + } + compareResults(t, &results[i], r) + } +} + +// compareResults asserts that two results are the same. +func compareResults(t *testing.T, expected, actual client.Result) { + t.Helper() + + require.NotNil(t, expected) + require.NotNil(t, actual) + require.Equal(t, expected.Round(), actual.Round()) + require.Equal(t, expected.Randomness(), actual.Randomness()) +} + +// fakeChainInfo creates a chain info object for use in tests. +func fakeChainInfo(t *testing.T) *chain.Info { + t.Helper() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + return &chain.Info{ + Period: time.Second, + GenesisTime: time.Now().Unix(), + PublicKey: test.GenerateIDs(1)[0].Public.Key, + Scheme: sch.Name, + } +} diff --git a/client/doc.go b/client/doc.go new file mode 100644 index 0000000..6ba72e3 --- /dev/null +++ b/client/doc.go @@ -0,0 +1,70 @@ +/* +Package client provides transport-agnostic logic to retrieve and verify +randomness from drand, including retry, validation, caching and +optimization features. + +Example: + + package main + + import ( + "context" + "encoding/hex" + "fmt" + + "github.com/drand/drand/client" + "github.com/drand/drand/common/log" + ) + + var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") + + func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + + c, err := client.New(ctx, lg, + client.From("..."), // see concrete client implementations + client.WithChainHash(chainHash), + ) + + // e.g. use the client to get the latest randomness round: + r, err := c.Get(ctx, 0) + + fmt.Println(r.Round(), r.Randomness()) + } + +The "From" option allows you to specify clients that work over particular +transports. HTTP, gRPC and libp2p PubSub clients are provided in drand's +subpackages https://pkg.go.dev/github.com/drand/drand/internal/client/http, +https://pkg.go.dev/github.com/drand/drand/internal/client/grpc and +https://pkg.go.dev/github.com/drand/drand/internal/lp2p/clientlp2p/client +respectively. Note that you are not restricted to just one client. You can use +multiple clients of the same type or of different types. The base client will +periodically "speed test" it's clients, failover, cache results and aggregate +calls to "Watch" to reduce requests. + +WARNING: When using the client you should use the "WithChainHash" or +"WithChainInfo" option in order for your client to validate the randomness it +receives is from the correct chain. You may use the "Insecurely" option to +bypass this validation but it is not recommended. + +In an application that uses the drand client, the following options are likely +to be needed/customized: + + WithCacheSize() + should be set to something sensible for your application. + + WithVerifiedResult() + WithFullChainVerification() + both should be set for increased security if you have + persistent state and expect to be following the chain. + + WithAutoWatch() + will pre-load new results as they become available adding them + to the cache for speedy retreival when you need them. + + WithPrometheus() + enables metrics reporting on speed and performance to a + provided prometheus registry. +*/ +package client diff --git a/client/empty.go b/client/empty.go new file mode 100644 index 0000000..7c1d24f --- /dev/null +++ b/client/empty.go @@ -0,0 +1,48 @@ +package client + +import ( + "context" + "time" + + "github.com/drand/drand/common" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/chain" +) + +const emptyClientStringerValue = "EmptyClient" + +// EmptyClientWithInfo makes a client that returns the given info but no randomness +func EmptyClientWithInfo(info *chain2.Info) client.Client { + return &emptyClient{info} +} + +type emptyClient struct { + i *chain2.Info +} + +func (m *emptyClient) String() string { + return emptyClientStringerValue +} + +func (m *emptyClient) Info(_ context.Context) (*chain2.Info, error) { + return m.i, nil +} + +func (m *emptyClient) RoundAt(t time.Time) uint64 { + return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) +} + +func (m *emptyClient) Get(_ context.Context, _ uint64) (client.Result, error) { + return nil, common.ErrEmptyClientUnsupportedGet +} + +func (m *emptyClient) Watch(_ context.Context) <-chan client.Result { + ch := make(chan client.Result, 1) + close(ch) + return ch +} + +func (m *emptyClient) Close() error { + return nil +} diff --git a/client/empty_test.go b/client/empty_test.go new file mode 100644 index 0000000..91d5427 --- /dev/null +++ b/client/empty_test.go @@ -0,0 +1,69 @@ +package client + +import ( + "context" + "fmt" + "testing" + "time" + + chain2 "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/chain" +) + +func TestEmptyClient(t *testing.T) { + chainInfo := fakeChainInfo(t) + c := EmptyClientWithInfo(chainInfo) + + // should be able to retrieve Info + i, err := c.Info(context.Background()) + if err != nil { + t.Fatal(err) + } + if i != chainInfo { + t.Fatal("unexpected chain info", i) + } + + // should be able to retrieve RoundAt + now := time.Now() + rnd := c.RoundAt(now) + if rnd != chain.CurrentRound(now.Unix(), chainInfo.Period, chainInfo.GenesisTime) { + t.Fatal("unexpected RoundAt return value", rnd) + } + + // should be fmt.Stringer + sc, ok := c.(fmt.Stringer) + if !ok { + t.Fatal("expected Stringer interface") + } + if sc.String() != emptyClientStringerValue { + t.Fatal("unexpected string value") + } + + // but Get does not work + _, err = c.Get(context.Background(), 0) + if err == nil { + t.Fatal("expected an error") + } + if err.Error() != "not supported" { + t.Fatal("unexpected error from Get", err) + } + + // and Watch returns an empty closed channel + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + ch := c.Watch(ctx) + //nolint + var rs []chain2.Result + for r := range ch { + rs = append(rs, r) + } + + if len(rs) > 0 { + t.Fatal("unexpected results in watch channel", rs) + } + + if err := c.Close(); err != nil { + t.Fatal("unexpected error closing client", err) + } +} diff --git a/client/grpc/client.go b/client/grpc/client.go new file mode 100644 index 0000000..f1b3483 --- /dev/null +++ b/client/grpc/client.go @@ -0,0 +1,148 @@ +package grpc + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "time" + + grpcProm "github.com/grpc-ecosystem/go-grpc-prometheus" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + grpcInsec "google.golang.org/grpc/credentials/insecure" + + "github.com/drand/drand/client" + chain2 "github.com/drand/drand/common/chain" + client2 "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/protobuf/common" + "github.com/drand/drand/protobuf/drand" +) + +const grpcDefaultTimeout = 5 * time.Second + +type grpcClient struct { + address string + chainHash []byte + client drand.PublicClient + conn *grpc.ClientConn + l log.Logger +} + +// New creates a drand client backed by a GRPC connection. +func New(l log.Logger, address, certPath string, insecure bool, chainHash []byte) (client2.Client, error) { + var opts []grpc.DialOption + if certPath != "" { + creds, err := credentials.NewClientTLSFromFile(certPath, "") + if err != nil { + return nil, err + } + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else if insecure { + opts = append(opts, grpc.WithTransportCredentials(grpcInsec.NewCredentials())) + } else { + opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}))) + } + opts = append(opts, + grpc.WithUnaryInterceptor(grpcProm.UnaryClientInterceptor), + grpc.WithStreamInterceptor(grpcProm.StreamClientInterceptor), + ) + conn, err := grpc.Dial(address, opts...) + if err != nil { + return nil, err + } + + return &grpcClient{address, chainHash, NewPublicClient(conn), conn, l}, nil +} + +func asRD(r *drand.PublicRandResponse) *client.RandomData { + return &client.RandomData{ + Rnd: r.Round, + Random: r.Randomness, + Sig: r.Signature, + PreviousSignature: r.PreviousSignature, + } +} + +// String returns the name of this client. +func (g *grpcClient) String() string { + return fmt.Sprintf("GRPC(%q)", g.address) +} + +// Get returns a the randomness at `round` or an error. +func (g *grpcClient) Get(ctx context.Context, round uint64) (client2.Result, error) { + curr, err := g.client.PublicRand(ctx, &drand.PublicRandRequest{Round: round, Metadata: g.getMetadata()}) + if err != nil { + return nil, err + } + if curr == nil { + return nil, errors.New("no received randomness - unexpected gPRC response") + } + + return asRD(curr), nil +} + +// Watch returns new randomness as it becomes available. +func (g *grpcClient) Watch(ctx context.Context) <-chan client2.Result { + stream, err := g.client.PublicRandStream(ctx, &drand.PublicRandRequest{Round: 0, Metadata: g.getMetadata()}) + ch := make(chan client2.Result, 1) + if err != nil { + close(ch) + return ch + } + go g.translate(stream, ch) + return ch +} + +// Info returns information about the chain. +func (g *grpcClient) Info(ctx context.Context) (*chain2.Info, error) { + proto, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) + if err != nil { + return nil, err + } + if proto == nil { + return nil, errors.New("no received group - unexpected gPRC response") + } + return chain2.InfoFromProto(proto) +} + +func (g *grpcClient) translate(stream drand.Public_PublicRandStreamClient, out chan<- client2.Result) { + defer close(out) + for { + next, err := stream.Recv() + if err != nil || stream.Context().Err() != nil { + if stream.Context().Err() == nil { + g.l.Warnw("", "grpc_client", "public rand stream", "err", err) + } + return + } + out <- asRD(next) + } +} + +func (g *grpcClient) getMetadata() *common.Metadata { + return &common.Metadata{ChainHash: g.chainHash} +} + +func (g *grpcClient) RoundAt(t time.Time) uint64 { + ctx, cancel := context.WithTimeout(context.Background(), grpcDefaultTimeout) + defer cancel() + + info, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) + if err != nil { + return 0 + } + return chain.CurrentRound(t.Unix(), time.Second*time.Duration(info.Period), info.GenesisTime) +} + +// SetLog configures the client log output +func (g *grpcClient) SetLog(l log.Logger) { + g.l = l +} + +// Close tears down the gRPC connection and all underlying connections. +func (g *grpcClient) Close() error { + return g.conn.Close() +} diff --git a/client/grpc/client_test.go b/client/grpc/client_test.go new file mode 100644 index 0000000..8d27feb --- /dev/null +++ b/client/grpc/client_test.go @@ -0,0 +1,114 @@ +package grpc + +import ( + "bytes" + "context" + "sync" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test/mock" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestClient(t *testing.T) { + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + l, server := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) + addr := l.Addr() + + go l.Start() + defer l.Stop(context.Background()) + + c, err := New(lg, addr, "", true, []byte("")) + if err != nil { + t.Fatal(err) + } + result, err := c.Get(context.Background(), 1969) + if err != nil { + t.Fatal(err) + } + if result.Round() != 1969 { + t.Fatal("unexpected round.") + } + r2, err := c.Get(context.Background(), 1970) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(r2.Randomness(), result.Randomness()) { + t.Fatal("unexpected equality") + } + + rat := c.RoundAt(time.Now()) + if rat == 0 { + t.Fatal("round at should function") + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + res := c.Watch(ctx) + go func() { + time.Sleep(50 * time.Millisecond) + server.(mock.Service).EmitRand(false) + }() + r3, ok := <-res + if !ok { + t.Fatal("watch should work") + } + if r3.Round() != 1971 { + t.Fatal("unexpected round") + } + cancel() + _ = c.Close() +} + +func TestClientClose(t *testing.T) { + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + l, _ := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) + addr := l.Addr() + + go l.Start() + defer l.Stop(context.Background()) + + c, err := New(lg, addr, "", true, []byte("")) + if err != nil { + t.Fatal(err) + } + result, err := c.Get(context.Background(), 1969) + if err != nil { + t.Fatal(err) + } + if result.Round() != 1969 { + t.Fatal("unexpected round.") + } + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + for range c.Watch(context.Background()) { + } + wg.Done() + }() + + err = c.Close() + if err != nil { + t.Fatal(err) + } + + _, err = c.Get(context.Background(), 0) + if status.Code(err) != codes.Canceled { + t.Fatal("unexpected error from closed client", err) + } + + wg.Wait() // wait for the watch to close +} diff --git a/client/grpc/doc.go b/client/grpc/doc.go new file mode 100644 index 0000000..6bb4ae3 --- /dev/null +++ b/client/grpc/doc.go @@ -0,0 +1,43 @@ +/* +Package grpc provides a drand client implementation that uses drand's gRPC API. + +The client connects to a drand gRPC endpoint to fetch randomness. The gRPC +client has some advantages over the HTTP client - it is more compact +on-the-wire and supports streaming and authentication. + +Example: + + package main + + import ( + "context" + "encoding/hex" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/grpc" + "github.com/drand/drand/common/log" + ) + + const ( + grpcAddr = "example.drand.grpc.server:4444" + certPath = "/path/to/drand-grpc.cert" + ) + + var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") + + func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + + gc, err := grpc.New(lg, grpcAddr, certPath, false, chainHash) + + c, err := client.New(ctx, lg, + client.From(gc), + ) + } + +A path to a file that holds TLS credentials for the drand server is required +to validate server connections. Alternatively set the final parameter to +`true` to enable _insecure_ connections (not recommended). +*/ +package grpc diff --git a/client/http/doc.go b/client/http/doc.go new file mode 100644 index 0000000..26b3c42 --- /dev/null +++ b/client/http/doc.go @@ -0,0 +1,45 @@ +/* +Package http provides a drand client implementation that uses drand's HTTP API. + +The HTTP client uses drand's JSON HTTP API +(https://drand.love/developer/http-api/) to fetch randomness. Watching is +implemented by polling the endpoint at the expected round time. + +Example: + + package main + + import ( + "context" + "encoding/hex" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/http" + "github.com/drand/drand/common/log" + ) + + var urls = []string{ + "https://api.drand.sh", + "https://drand.cloudflare.com", + } + + var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") + + func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + + c, err := client.New(ctx, lg, + client.From(http.ForURLs(ctx, lg, urls, chainHash)...), + client.WithChainHash(chainHash), + ) + } + +The "ForURLs" helper creates multiple HTTP clients from a list of +URLs. Alternatively you can use the "New" or "NewWithInfo" constructor to +create clients. + +Tip: Provide multiple URLs to enable failover and speed optimized URL +selection. +*/ +package http diff --git a/client/http/http.go b/client/http/http.go new file mode 100644 index 0000000..bb81e92 --- /dev/null +++ b/client/http/http.go @@ -0,0 +1,401 @@ +package http + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + nhttp "net/http" + "os" + "path" + "strings" + "time" + + json "github.com/nikkolasg/hexjson" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + + client2 "github.com/drand/drand/client" + "github.com/drand/drand/common" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/metrics" +) + +var errClientClosed = fmt.Errorf("client closed") + +const defaultClientExec = "unknown" +const defaultHTTTPTimeout = 60 * time.Second + +const httpWaitMaxCounter = 20 +const httpWaitInterval = 2 * time.Second +const maxTimeoutHTTPRequest = 5 * time.Second + +// New creates a new client pointing to an HTTP endpoint +func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transport nhttp.RoundTripper) (client.Client, error) { + if transport == nil { + transport = nhttp.DefaultTransport + } + if !strings.HasSuffix(url, "/") { + url += "/" + } + pn, err := os.Executable() + if err != nil { + pn = defaultClientExec + } + agent := fmt.Sprintf("drand-client-%s/1.0", path.Base(pn)) + c := &httpClient{ + root: url, + client: instrumentClient(url, transport), + l: l, + Agent: agent, + done: make(chan struct{}), + } + + ctx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() + + chainInfo, err := c.FetchChainInfo(ctx, chainHash) + if err != nil { + return nil, err + } + c.chainInfo = chainInfo + + return c, nil +} + +// NewWithInfo constructs an http client when the group parameters are already known. +func NewWithInfo(l log.Logger, url string, info *chain2.Info, transport nhttp.RoundTripper) (client.Client, error) { + if transport == nil { + transport = nhttp.DefaultTransport + } + if !strings.HasSuffix(url, "/") { + url += "/" + } + + pn, err := os.Executable() + if err != nil { + pn = defaultClientExec + } + agent := fmt.Sprintf("drand-client-%s/1.0", path.Base(pn)) + c := &httpClient{ + root: url, + chainInfo: info, + client: instrumentClient(url, transport), + l: l, + Agent: agent, + done: make(chan struct{}), + } + return c, nil +} + +// ForURLs provides a shortcut for creating a set of HTTP clients for a set of URLs. +func ForURLs(ctx context.Context, l log.Logger, urls []string, chainHash []byte) []client.Client { + clients := make([]client.Client, 0) + var info *chain2.Info + var skipped []string + for _, u := range urls { + if info == nil { + if c, err := New(ctx, l, u, chainHash, nil); err == nil { + // Note: this wrapper assumes the current behavior that if `New` succeeds, + // Info will have been fetched. + info, _ = c.Info(ctx) + clients = append(clients, c) + } else { + skipped = append(skipped, u) + } + } else { + if c, err := NewWithInfo(l, u, info, nil); err == nil { + clients = append(clients, c) + } + } + } + if info != nil { + for _, u := range skipped { + if c, err := NewWithInfo(l, u, info, nil); err == nil { + clients = append(clients, c) + } + } + } + return clients +} + +func Ping(ctx context.Context, root string) error { + url := fmt.Sprintf("%s/health", root) + + ctx, cancel := context.WithTimeout(ctx, maxTimeoutHTTPRequest) + defer cancel() + + req, err := nhttp.NewRequestWithContext(ctx, nhttp.MethodGet, url, nhttp.NoBody) + if err != nil { + return fmt.Errorf("creating request: %w", err) + } + + response, err := nhttp.DefaultClient.Do(req) + if err != nil { + return fmt.Errorf("creating request: %w", err) + } + + defer response.Body.Close() + + return nil +} + +// Instruments an HTTP client around a transport +func instrumentClient(url string, transport nhttp.RoundTripper) *nhttp.Client { + hc := nhttp.Client{} + hc.Timeout = defaultHTTTPTimeout + hc.Jar = nhttp.DefaultClient.Jar + hc.CheckRedirect = nhttp.DefaultClient.CheckRedirect + urlLabel := prometheus.Labels{"url": url} + + trace := &promhttp.InstrumentTrace{ + DNSStart: func(t float64) { + metrics.ClientDNSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("dns_start").Observe(t) + }, + DNSDone: func(t float64) { + metrics.ClientDNSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("dns_done").Observe(t) + }, + TLSHandshakeStart: func(t float64) { + metrics.ClientTLSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("tls_handshake_start").Observe(t) + }, + TLSHandshakeDone: func(t float64) { + metrics.ClientTLSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("tls_handshake_done").Observe(t) + }, + } + + transport = promhttp.InstrumentRoundTripperInFlight(metrics.ClientInFlight.With(urlLabel), + promhttp.InstrumentRoundTripperCounter(metrics.ClientRequests.MustCurryWith(urlLabel), + promhttp.InstrumentRoundTripperTrace(trace, + promhttp.InstrumentRoundTripperDuration(metrics.ClientLatencyVec.MustCurryWith(urlLabel), + transport)))) + + hc.Transport = transport + + return &hc +} + +func IsServerReady(ctx context.Context, addr string) (er error) { + counter := 0 + for { + // Ping is wrapping its context with a Timeout on maxTimeoutHTTPRequest anyway. + err := Ping(ctx, "http://"+addr) + if err == nil { + return nil + } + + counter++ + if counter == httpWaitMaxCounter { + return fmt.Errorf("timeout waiting http server to be ready") + } + + time.Sleep(httpWaitInterval) + } +} + +// httpClient implements Client through http requests to a Drand relay. +type httpClient struct { + root string + client *nhttp.Client + Agent string + chainInfo *chain2.Info + l log.Logger + done chan struct{} +} + +// SetLog configures the client log output +func (h *httpClient) SetLog(l log.Logger) { + h.l = l +} + +// SetUserAgent sets the user agent used by the client +func (h *httpClient) SetUserAgent(ua string) { + h.Agent = ua +} + +// String returns the name of this client. +func (h *httpClient) String() string { + return fmt.Sprintf("HTTP(%q)", h.root) +} + +// MarshalText implements encoding.TextMarshaller interface +func (h *httpClient) MarshalText() ([]byte, error) { + return json.Marshal(h.String()) +} + +type httpInfoResponse struct { + chainInfo *chain2.Info + err error +} + +// FetchChainInfo attempts to initialize an httpClient when +// it does not know the full group parameters for a drand group. The chain hash +// is the hash of the chain info. +func (h *httpClient) FetchChainInfo(ctx context.Context, chainHash []byte) (*chain2.Info, error) { + if h.chainInfo != nil { + return h.chainInfo, nil + } + + resC := make(chan httpInfoResponse, 1) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + go func() { + var url string + if len(chainHash) > 0 { + url = fmt.Sprintf("%s%x/info", h.root, chainHash) + } else { + url = fmt.Sprintf("%sinfo", h.root) + } + + req, err := nhttp.NewRequestWithContext(ctx, nhttp.MethodGet, url, nhttp.NoBody) + if err != nil { + resC <- httpInfoResponse{nil, fmt.Errorf("creating request: %w", err)} + return + } + req.Header.Set("User-Agent", h.Agent) + + infoBody, err := h.client.Do(req) + if err != nil { + resC <- httpInfoResponse{nil, fmt.Errorf("doing request: %w", err)} + return + } + defer infoBody.Body.Close() + + chainInfo, err := chain2.InfoFromJSON(infoBody.Body) + if err != nil { + resC <- httpInfoResponse{nil, fmt.Errorf("decoding response: %w", err)} + return + } + + if chainInfo.PublicKey == nil { + resC <- httpInfoResponse{nil, fmt.Errorf("group does not have a valid key for validation")} + return + } + + if len(chainHash) == 0 { + h.l.Warnw("", "http_client", "instantiated without trustroot", "chainHash", hex.EncodeToString(chainInfo.Hash())) + if !common.IsDefaultBeaconID(chainInfo.ID) { + err := fmt.Errorf("%s does not advertise the default drand for the default chainHash (got %x)", h.root, chainInfo.Hash()) + resC <- httpInfoResponse{nil, err} + return + } + } else if !bytes.Equal(chainInfo.Hash(), chainHash) { + err := fmt.Errorf("%s does not advertise the expected drand group (%x vs %x)", h.root, chainInfo.Hash(), chainHash) + resC <- httpInfoResponse{nil, err} + return + } + resC <- httpInfoResponse{chainInfo, nil} + }() + + select { + case res := <-resC: + if res.err != nil { + return nil, res.err + } + return res.chainInfo, nil + case <-h.done: + return nil, errClientClosed + } +} + +type httpGetResponse struct { + result client.Result + err error +} + +// Get returns the randomness at `round` or an error. +func (h *httpClient) Get(ctx context.Context, round uint64) (client.Result, error) { + var url string + if round == 0 { + url = fmt.Sprintf("%s%x/public/latest", h.root, h.chainInfo.Hash()) + } else { + url = fmt.Sprintf("%s%x/public/%d", h.root, h.chainInfo.Hash(), round) + } + + resC := make(chan httpGetResponse, 1) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + go func() { + req, err := nhttp.NewRequestWithContext(ctx, nhttp.MethodGet, url, nhttp.NoBody) + if err != nil { + resC <- httpGetResponse{nil, fmt.Errorf("creating request: %w", err)} + return + } + req.Header.Set("User-Agent", h.Agent) + + randResponse, err := h.client.Do(req) + if err != nil { + resC <- httpGetResponse{nil, fmt.Errorf("doing request: %w", err)} + return + } + defer randResponse.Body.Close() + + randResp := client2.RandomData{} + if err := json.NewDecoder(randResponse.Body).Decode(&randResp); err != nil { + resC <- httpGetResponse{nil, fmt.Errorf("decoding response: %w", err)} + return + } + + if len(randResp.Sig) == 0 { + resC <- httpGetResponse{nil, fmt.Errorf("insufficient response - signature is not present")} + return + } + + resC <- httpGetResponse{&randResp, nil} + }() + + select { + case res := <-resC: + if res.err != nil { + return nil, res.err + } + return res.result, nil + case <-h.done: + return nil, errClientClosed + } +} + +// Watch returns new randomness as it becomes available. +func (h *httpClient) Watch(ctx context.Context) <-chan client.Result { + out := make(chan client.Result) + go func() { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + defer close(out) + + in := client2.PollingWatcher(ctx, h, h.chainInfo, h.l) + for { + select { + case res, ok := <-in: + if !ok { + return + } + out <- res + case <-h.done: + return + } + } + }() + return out +} + +// Info returns information about the chain. +func (h *httpClient) Info(_ context.Context) (*chain2.Info, error) { + return h.chainInfo, nil +} + +// RoundAt will return the most recent round of randomness that will be available +// at time for the current client. +func (h *httpClient) RoundAt(t time.Time) uint64 { + return chain.CurrentRound(t.Unix(), h.chainInfo.Period, h.chainInfo.GenesisTime) +} + +func (h *httpClient) Close() error { + close(h.done) + h.client.CloseIdleConnections() + return nil +} diff --git a/client/http/http_test.go b/client/http/http_test.go new file mode 100644 index 0000000..f5c62f5 --- /dev/null +++ b/client/http/http_test.go @@ -0,0 +1,301 @@ +package http + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net" + "net/http" + "sync" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/test/http/mock" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestHTTPClient(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, true, sch, clk) + defer cancel() + + err = IsServerReady(ctx, addr) + if err != nil { + t.Fatal(err) + } + + l := testlogger.New(t) + httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + if err != nil { + t.Fatal(err) + } + + ctx1, cancel1 := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel1() + result, err := httpClient.Get(ctx1, 0) + if err != nil { + t.Fatal(err) + } + if len(result.Randomness()) == 0 { + t.Fatal("no randomness provided") + } + full, ok := (result).(*client.RandomData) + if !ok { + t.Fatal("Should be able to restore concrete type") + } + if len(full.Sig) == 0 { + t.Fatal("no signature provided") + } + + ctx2, cancel2 := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel2() + if _, err := httpClient.Get(ctx2, full.Rnd+1); err != nil { + t.Fatalf("http client should not perform verification of results. err: %s", err) + } + _ = httpClient.Close() +} + +func TestHTTPGetLatest(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + err = IsServerReady(ctx, addr) + if err != nil { + t.Fatal(err) + } + + l := testlogger.New(t) + httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + if err != nil { + t.Fatal(err) + } + + ctx, cancel = context.WithTimeout(ctx, time.Second) + defer cancel() + r0, err := httpClient.Get(ctx, 0) + if err != nil { + t.Fatal(err) + } + + ctx, cancel = context.WithTimeout(ctx, time.Second) + defer cancel() + r1, err := httpClient.Get(ctx, 0) + if err != nil { + t.Fatal(err) + } + + if r1.Round() != r0.Round()+1 { + t.Fatal("expected round progression") + } + _ = httpClient.Close() +} + +func TestForURLsCreation(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + err = IsServerReady(ctx, addr) + if err != nil { + t.Fatal(err) + } + + l := testlogger.New(t) + clients := ForURLs(ctx, l, []string{"http://invalid.domain/", "http://" + addr}, chainInfo.Hash()) + if len(clients) != 2 { + t.Fatal("expect both urls returned") + } + _ = clients[0].Close() + _ = clients[1].Close() +} + +func TestHTTPWatch(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + err = IsServerReady(ctx, addr) + if err != nil { + t.Fatal(err) + } + + l := testlogger.New(t) + httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + if err != nil { + t.Fatal(err) + } + + ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + result := httpClient.Watch(ctx) + first, ok := <-result + if !ok { + t.Fatal("should get a result from watching") + } + if len(first.Randomness()) == 0 { + t.Fatal("should get randomness from watching") + } + + for range result { + } + _ = httpClient.Close() +} + +func TestHTTPClientClose(t *testing.T) { + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + err = IsServerReady(ctx, addr) + if err != nil { + t.Fatal(err) + } + + l := testlogger.New(t) + httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + if err != nil { + t.Fatal(err) + } + result, err := httpClient.Get(context.Background(), 1969) + if err != nil { + t.Fatal(err) + } + if result.Round() != 1969 { + t.Fatal("unexpected round.") + } + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + for range httpClient.Watch(context.Background()) { + } + wg.Done() + }() + + err = httpClient.Close() + if err != nil { + t.Fatal(err) + } + + _, err = httpClient.Get(context.Background(), 0) + if !errors.Is(err, errClientClosed) { + t.Fatal("unexpected error from closed client", err) + } + + wg.Wait() // wait for the watch to close +} + +//nolint:funlen +func TestHTTPRelay(t *testing.T) { + lg := testlogger.New(t) + ctx := log.ToContext(context.Background(), lg) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + test.Tracer(t, ctx) + + clk := clock.NewFakeClockAt(time.Now()) + c, _ := withClient(t, clk) + + handler, err := New(ctx, "") + if err != nil { + t.Fatal(err) + } + + info, err := c.Info(ctx) + if err != nil { + t.Fatal(err) + } + + handler.RegisterNewBeaconHandler(c, info.HashString()) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + server := http.Server{Handler: handler.GetHTTPHandler()} + go func() { _ = server.Serve(listener) }() + defer func() { _ = server.Shutdown(ctx) }() + + err = nhttp.IsServerReady(ctx, listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + + getChains := fmt.Sprintf("http://%s/chains", listener.Addr().String()) + resp := getWithCtx(ctx, getChains, t) + if resp.StatusCode != http.StatusOK { + t.Error("expected http status code 200") + } + var chains []string + require.NoError(t, json.NewDecoder(resp.Body).Decode(&chains)) + require.NoError(t, resp.Body.Close()) + + if len(chains) != 1 { + t.Error("expected chain hash qty not valid") + } + if chains[0] != info.HashString() { + t.Error("expected chain hash not valid") + } + + getChain := fmt.Sprintf("http://%s/%s/info", listener.Addr().String(), info.HashString()) + resp = getWithCtx(ctx, getChain, t) + cip := new(drand.ChainInfoPacket) + require.NoError(t, json.NewDecoder(resp.Body).Decode(cip)) + require.NotNil(t, cip.Hash) + require.NotNil(t, cip.PublicKey) + require.NoError(t, resp.Body.Close()) + + // Test exported interfaces. + u := fmt.Sprintf("http://%s/%s/public/2", listener.Addr().String(), info.HashString()) + resp = getWithCtx(ctx, u, t) + body := make(map[string]interface{}) + require.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) + require.NoError(t, resp.Body.Close()) + + if _, ok := body["signature"]; !ok { + t.Fatal("expected signature in random response.") + } + + u = fmt.Sprintf("http://%s/%s/public/latest", listener.Addr().String(), info.HashString()) + resp, err = http.Get(u) + if err != nil { + t.Fatal(err) + } + body = make(map[string]interface{}) + + if err = json.NewDecoder(resp.Body).Decode(&body); err != nil { + t.Fatal(err) + } + require.NoError(t, resp.Body.Close()) + + if _, ok := body["round"]; !ok { + t.Fatal("expected signature in latest response.") + } +} diff --git a/client/http/metric.go b/client/http/metric.go new file mode 100644 index 0000000..2180ba9 --- /dev/null +++ b/client/http/metric.go @@ -0,0 +1,67 @@ +package http + +import ( + "context" + "time" + + "github.com/prometheus/client_golang/prometheus" + + chain2 "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/metrics" +) + +// MeasureHeartbeats periodically tracks latency observed on a set of HTTP clients +func MeasureHeartbeats(ctx context.Context, c []chain2.Client) *HealthMetrics { + m := &HealthMetrics{ + next: 0, + clients: c, + } + if len(c) > 0 { + go m.startObserve(ctx) + } + return m +} + +// HealthMetrics is a measurement task around HTTP clients +type HealthMetrics struct { + next int + clients []chain2.Client +} + +// HeartbeatInterval is the duration between liveness heartbeats sent to an HTTP API. +const HeartbeatInterval = 10 * time.Second + +func (c *HealthMetrics) startObserve(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + default: + } + time.Sleep(time.Duration(int64(HeartbeatInterval) / int64(len(c.clients)))) + n := c.next % len(c.clients) + + httpClient, ok := c.clients[n].(*httpClient) + if !ok { + c.next++ + continue + } + + result, err := c.clients[n].Get(ctx, c.clients[n].RoundAt(time.Now())+1) + if err != nil { + metrics.ClientHTTPHeartbeatFailure.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + continue + } + + metrics.ClientHTTPHeartbeatSuccess.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + + // compute the latency metric + actual := time.Now().UnixNano() + expected := chain.TimeOfRound(httpClient.chainInfo.Period, httpClient.chainInfo.GenesisTime, result.Round()) * 1e9 + // the labels of the gauge vec must already be set at the registerer level + metrics.ClientHTTPHeartbeatLatency.With(prometheus.Labels{"http_address": httpClient.root}). + Set(float64(actual-expected) / float64(time.Millisecond)) + c.next++ + } +} diff --git a/client/lp2p/client.go b/client/lp2p/client.go new file mode 100644 index 0000000..9e204eb --- /dev/null +++ b/client/lp2p/client.go @@ -0,0 +1,254 @@ +package lp2p + +import ( + "context" + "encoding/hex" + "fmt" + "sync" + + clock "github.com/jonboulle/clockwork" + "github.com/libp2p/go-libp2p" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + "google.golang.org/protobuf/proto" + + client2 "github.com/drand/drand/client" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/lp2p" + "github.com/drand/drand/protobuf/drand" +) + +// Client is a concrete pubsub client implementation +type Client struct { + cancel func() + latest uint64 + cache client2.Cache + bufferSize int + log log.Logger + + subs struct { + sync.Mutex + M map[*int]chan drand.PublicRandResponse + } +} + +// DefaultBufferSize controls how many incoming messages can be in-flight until they start +// to be dropped by the library +const DefaultBufferSize = 100 + +// SetLog configures the client log output +func (c *Client) SetLog(l log.Logger) { + c.log = l +} + +// WithPubsub provides an option for integrating pubsub notification +// into a drand client. +func WithPubsub(l log.Logger, ps *pubsub.PubSub, clk clock.Clock, bufferSize int) client2.Option { + return client2.WithWatcher(func(info *chain.Info, cache client2.Cache) (client2.Watcher, error) { + c, err := NewWithPubsub(l, ps, info, cache, clk, bufferSize) + if err != nil { + return nil, err + } + return c, nil + }) +} + +// NewWithPubsub creates a gossip randomness client. +// +//nolint:funlen,lll // This is the correct function length +func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache client2.Cache, clk clock.Clock, bufferSize int) (*Client, error) { + if info == nil { + return nil, fmt.Errorf("no chain supplied for joining") + } + + ctx, cancel := context.WithCancel(context.Background()) + c := &Client{ + cancel: cancel, + cache: cache, + bufferSize: bufferSize, + log: l, + } + + chainHash := hex.EncodeToString(info.Hash()) + topic := lp2p.PubSubTopic(chainHash) + if err := ps.RegisterTopicValidator(topic, randomnessValidator(info, cache, c, clk)); err != nil { + cancel() + return nil, fmt.Errorf("creating topic: %w", err) + } + t, err := ps.Join(topic) + if err != nil { + cancel() + return nil, fmt.Errorf("joining pubsub: %w", err) + } + s, err := t.Subscribe() + if err != nil { + cancel() + return nil, fmt.Errorf("subscribe: %w", err) + } + + c.subs.M = make(map[*int]chan drand.PublicRandResponse) + + go func() { + for { + msg, err := s.Next(ctx) + if ctx.Err() != nil { + c.log.Debugw("NewPubSub closing because context was canceled", "msg", msg, "err", ctx.Err()) + + s.Cancel() + err := t.Close() + if err != nil { + c.log.Errorw("NewPubSub closing goroutine for topic", "err", err) + } + + c.subs.Lock() + for _, ch := range c.subs.M { + close(ch) + } + c.subs.M = make(map[*int]chan drand.PublicRandResponse) + c.subs.Unlock() + return + } + if err != nil { + c.log.Warnw("", "gossip client", "topic.Next error", "err", err) + continue + } + + var rand drand.PublicRandResponse + err = proto.Unmarshal(msg.Data, &rand) + if err != nil { + c.log.Warnw("", "gossip client", "unmarshal random error", "err", err) + continue + } + + // TODO: verification, need to pass drand network public key in + + if c.latest >= rand.Round { + c.log.Debugw("received round older than the latest previously received one", "latest", c.latest, "round", rand.Round) + continue + } + c.latest = rand.Round + + c.log.Debugw("newPubSub broadcasting round to listeners", "round", rand.Round) + c.subs.Lock() + for _, ch := range c.subs.M { + select { + case ch <- rand: + default: + c.log.Warnw("", "gossip client", "randomness notification dropped due to a full channel") + } + } + c.subs.Unlock() + c.log.Debugw("newPubSub finished broadcasting round to listeners", "round", rand.Round) + } + }() + + return c, nil +} + +// UnsubFunc is a cancel function for pubsub subscription +type UnsubFunc func() + +// Sub subscribes to notfications about new randomness. +// Client instance owns the channel after it is passed to Sub function, +// thus the channel should not be closed by library user +// +// It is recommended to use a buffered channel. If the channel is full, +// notification about randomness will be dropped. +// +// Notification channels will be closed when the client is Closed +func (c *Client) Sub(ch chan drand.PublicRandResponse) UnsubFunc { + id := new(int) + c.subs.Lock() + c.subs.M[id] = ch + c.subs.Unlock() + return func() { + c.log.Debugw("closing sub") + c.subs.Lock() + delete(c.subs.M, id) + close(ch) + c.subs.Unlock() + } +} + +// Watch implements the client.Watcher interface +func (c *Client) Watch(ctx context.Context) <-chan client.Result { + innerCh := make(chan drand.PublicRandResponse, c.bufferSize) + outerCh := make(chan client.Result, c.bufferSize) + end := c.Sub(innerCh) + + w := sync.WaitGroup{} + w.Add(1) + + go func() { + defer close(outerCh) + + w.Done() + + for { + select { + // TODO: do not copy by assignment any drand.PublicRandResponse + case resp, ok := <-innerCh: //nolint:govet + if !ok { + return + } + dat := &client2.RandomData{ + Rnd: resp.Round, + Random: resp.Randomness, + Sig: resp.Signature, + PreviousSignature: resp.PreviousSignature, + } + if c.cache != nil { + c.cache.Add(resp.Round, dat) + } + select { + case outerCh <- dat: + c.log.Debugw("processed random beacon", "round", dat.Round()) + default: + c.log.Warnw("", "gossip client", "randomness notification dropped due to a full channel", "round", dat.Round()) + } + case <-ctx.Done(): + c.log.Debugw("client.Watch done") + end() + // drain leftover on innerCh + for range innerCh { + } + c.log.Debugw("client.Watch finished draining the innerCh") + return + } + } + }() + + w.Wait() + + return outerCh +} + +// Close stops Client, cancels PubSub subscription and closes the topic. +func (c *Client) Close() error { + c.cancel() + return nil +} + +// NewPubsub constructs a basic libp2p pubsub module for use with the drand client. +func NewPubsub(ctx context.Context, listenAddr, relayAddr string) (*pubsub.PubSub, error) { + h, err := libp2p.New(libp2p.ListenAddrStrings(listenAddr)) + if err != nil { + return nil, err + } + + relayMa, err := multiaddr.NewMultiaddr(relayAddr) + if err != nil { + return nil, err + } + + relayAi, err := peer.AddrInfoFromP2pAddr(relayMa) + if err != nil { + return nil, err + } + + dps := []peer.AddrInfo{*relayAi} + return pubsub.NewGossipSub(ctx, h, pubsub.WithDirectPeers(dps)) +} diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go new file mode 100644 index 0000000..d821440 --- /dev/null +++ b/client/lp2p/client_test.go @@ -0,0 +1,246 @@ +package lp2p + +import ( + "context" + "fmt" + "net/http" + "path" + "testing" + "time" + + bds "github.com/ipfs/go-ds-badger2" + clock "github.com/jonboulle/clockwork" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + + "github.com/drand/drand/client/grpc" + dhttp "github.com/drand/drand/client/http" + httpmock "github.com/drand/drand/client/test/http/mock" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/lp2p" + "github.com/drand/drand/internal/test" + "github.com/drand/drand/internal/test/mock" + "github.com/drand/drand/internal/test/testlogger" +) + +func TestGRPCClientTestFunc(t *testing.T) { + lg := testlogger.New(t) + // start mock drand node + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + + clk := clock.NewFakeClockAt(time.Now()) + + grpcLis, svc := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) + grpcAddr := grpcLis.Addr() + go grpcLis.Start() + defer grpcLis.Stop(context.Background()) + + dataDir := t.TempDir() + identityDir := t.TempDir() + + infoProto, err := svc.ChainInfo(context.Background(), nil) + require.NoError(t, err) + + info, err := chain2.InfoFromProto(infoProto) + require.NoError(t, err) + + // start mock relay-node + grpcClient, err := grpc.New(lg, grpcAddr, "", true, []byte("")) + require.NoError(t, err) + + cfg := &lp2p.GossipRelayConfig{ + ChainHash: info.HashString(), + PeerWith: nil, + Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), + DataDir: dataDir, + IdentityPath: path.Join(identityDir, "identity.key"), + Client: grpcClient, + } + g, err := lp2p.NewGossipRelayNode(lg, cfg) + require.NoError(t, err, "gossip relay node") + + defer g.Shutdown() + + // start client + c, err := newTestClient(t, g.Multiaddrs(), info, clk) + require.NoError(t, err) + defer func() { + err := c.Close() + require.NoError(t, err) + }() + + // test client + ctx, cancel := context.WithCancel(context.Background()) + ch := c.Watch(ctx) + + baseRound := uint64(1969) + + mockService := svc.(mock.Service) + // pub sub polls every 200ms + wait := 250 * time.Millisecond + for i := uint64(0); i < 3; i++ { + time.Sleep(wait) + mockService.EmitRand(false) + t.Logf("round %d emitted\n", baseRound+i) + + select { + case r, ok := <-ch: + require.True(t, ok, "expected randomness, watch outer channel was closed instead") + t.Logf("received round %d\n", r.Round()) + require.Equal(t, baseRound+i, r.Round()) + // the period of the mock servers is 1 second + case <-time.After(5 * time.Second): + t.Fatal("timeout.") + } + } + + time.Sleep(wait) + mockService.EmitRand(true) + cancel() + + drain(t, ch, 5*time.Second) +} + +func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { + for { + select { + case _, ok := <-ch: + if !ok { + return + } + case <-time.After(timeout): + t.Fatal("timed out closing channel.") + } + } +} + +func TestHTTPClientTestFunc(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow test in short mode.") + } + + ctx := context.Background() + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + + clk := clock.NewFakeClockAt(time.Now()) + + addr, chainInfo, stop, emit := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer stop() + + dataDir := t.TempDir() + identityDir := t.TempDir() + + httpClient, err := dhttp.New(ctx, lg, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + require.NoError(t, err) + + cfg := &lp2p.GossipRelayConfig{ + ChainHash: chainInfo.HashString(), + PeerWith: nil, + Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), + DataDir: dataDir, + IdentityPath: path.Join(identityDir, "identity.key"), + Client: httpClient, + } + g, err := lp2p.NewGossipRelayNode(lg, cfg) + if err != nil { + t.Fatalf("gossip relay node (%v)", err) + } + defer g.Shutdown() + + c, err := newTestClient(t, g.Multiaddrs(), chainInfo, clk) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + ctx, cancel := context.WithCancel(ctx) + emit(false) + ch := c.Watch(ctx) + for i := 0; i < 3; i++ { + // pub sub polls every 200ms, but the other http one polls every period + time.Sleep(1250 * time.Millisecond) + emit(false) + select { + case r, ok := <-ch: + if !ok { + t.Fatal("expected randomness") + } else { + t.Log("received randomness", r.Round()) + } + case <-time.After(8 * time.Second): + t.Fatal("timeout.") + } + } + emit(true) + cancel() + drain(t, ch, 5*time.Second) +} + +func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { + dataDir := t.TempDir() + identityDir := t.TempDir() + ds, err := bds.NewDatastore(dataDir, nil) + if err != nil { + return nil, err + } + lg := testlogger.New(t) + priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) + if err != nil { + return nil, err + } + h, ps, err := lp2p.ConstructHost( + ds, + priv, + "/ip4/0.0.0.0/tcp/"+test.FreePort(), + relayMultiaddr, + lg, + ) + if err != nil { + return nil, err + } + relayPeerID, err := peerIDFromMultiaddr(relayMultiaddr[0]) + if err != nil { + return nil, err + } + err = waitForConnection(h, relayPeerID, time.Minute) + if err != nil { + return nil, err + } + c, err := NewWithPubsub(lg, ps, info, nil, clk, 100) + if err != nil { + return nil, err + } + c.SetLog(lg) + return c, nil +} + +func peerIDFromMultiaddr(addr ma.Multiaddr) (peer.ID, error) { + ai, err := peer.AddrInfoFromP2pAddr(addr) + if err != nil { + return "", err + } + return ai.ID, nil +} + +func waitForConnection(h host.Host, id peer.ID, timeout time.Duration) error { + t := time.NewTimer(timeout) + for { + if len(h.Network().ConnsToPeer(id)) > 0 { + t.Stop() + return nil + } + select { + case <-t.C: + return fmt.Errorf("timed out waiting to be connected the relay @ %v", id) + default: + } + time.Sleep(time.Millisecond * 100) + } +} diff --git a/client/lp2p/doc.go b/client/lp2p/doc.go new file mode 100644 index 0000000..91c5597 --- /dev/null +++ b/client/lp2p/doc.go @@ -0,0 +1,97 @@ +/* +Package lp2p provides a drand client implementation that retrieves +randomness by subscribing to a libp2p pubsub topic. + +WARNING: this client can only be used to "Watch" for new randomness rounds and +"Get" randomness rounds it has previously seen that are still in the cache. + +If you need to "Get" arbitrary rounds from the chain then you must combine this client with the http or grpc clients. + +The agnostic client builder must receive "WithChainInfo()" in order for it to +validate randomness rounds it receives, or "WithChainHash()" and be combined +with the HTTP or gRPC client implementations so that chain information can be +fetched from them. + +It is particularly important that rounds are verified since they can be delivered by any peer in the network. + +Example using "WithChainInfo()": + + package main + + import ( + "context" + + clock "github.com/jonboulle/clockwork" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/drand/drand/client" + gclient "github.com/drand/drand/client/lp2p" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/log" + ) + + func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + clk := clock.NewRealClock() + + ps := newPubSub() + info := readChainInfo() + + c, err := client.New(ctx, lg, + gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), + client.WithChainInfo(info), + ) + } + + func newPubSub() *pubsub.Pubsub { + // ... + } + + func readChainInfo() *chain.Info { + // ... + } + +Example using "WithChainHash()" and combining it with a different client: + + package main + + import ( + "context" + "encoding/hex" + + clock "github.com/jonboulle/clockwork" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/http" + gclient "github.com/drand/drand/client/lp2p" + "github.com/drand/drand/common/log" + ) + + var urls = []string{ + "https://api.drand.sh", + "https://drand.cloudflare.com", + // ... + } + + var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") + + func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + clk := clock.NewRealClock() + ps := newPubSub() + + c, err := client.New(ctx, lg, + gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), + client.WithChainHash(chainHash), + client.From(http.ForURLs(ctx, lg, urls, chainHash)...), + ) + } + + func newPubSub() *pubsub.Pubsub { + // ... + } +*/ +package lp2p diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go new file mode 100644 index 0000000..91b1d2b --- /dev/null +++ b/client/lp2p/validator.go @@ -0,0 +1,90 @@ +package lp2p + +import ( + "bytes" + "context" + "time" + + clock "github.com/jonboulle/clockwork" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/libp2p/go-libp2p/core/peer" + "google.golang.org/protobuf/proto" + + client2 "github.com/drand/drand/client" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/protobuf/drand" +) + +func randomnessValidator(info *chain2.Info, cache client2.Cache, c *Client, clk clock.Clock) pubsub.ValidatorEx { + return func(ctx context.Context, p peer.ID, m *pubsub.Message) pubsub.ValidationResult { + rand := &drand.PublicRandResponse{} + err := proto.Unmarshal(m.Data, rand) + if err != nil { + c.log.Warnw("", "gossip validator", "Not validating received randomness due to proto.Unmarshal error", "err", err) + return pubsub.ValidationReject + } + + c.log.Debugw("", "gossip validator", "Received new round", "round", rand.GetRound()) + + if info == nil { + c.log.Warnw("", "gossip validator", "Not validating received randomness due to lack of trust root.") + return pubsub.ValidationAccept + } + + // Unwilling to relay beacons in the future. + timeNow := clk.Now() + timeOfRound := chain.TimeOfRound(info.Period, info.GenesisTime, rand.GetRound()) + if time.Unix(timeOfRound, 0).After(timeNow) { + c.log.Warnw("", + "gossip validator", "Not validating received randomness due to time of round", + "err", err, + "timeOfRound", timeOfRound, + "time.Now", timeNow.Unix(), + "info.Period", info.Period, + "info.Genesis", info.GenesisTime, + "round", rand.GetRound(), + ) + return pubsub.ValidationReject + } + + if cache != nil { + if current := cache.TryGet(rand.GetRound()); current != nil { + currentFull, ok := current.(*client2.RandomData) + if !ok { + // Note: this shouldn't happen in practice, but if we have a + // degraded cache entry we can't validate the full byte + // sequence. + if bytes.Equal(rand.GetSignature(), current.Signature()) { + c.log.Warnw("", "gossip validator", "ignore") + return pubsub.ValidationIgnore + } + c.log.Warnw("", "gossip validator", "reject") + return pubsub.ValidationReject + } + if current.Round() == rand.GetRound() && + bytes.Equal(current.Randomness(), rand.GetRandomness()) && + bytes.Equal(current.Signature(), rand.GetSignature()) && + bytes.Equal(currentFull.PreviousSignature, rand.GetPreviousSignature()) { + c.log.Warnw("", "gossip validator", "ignore") + return pubsub.ValidationIgnore + } + c.log.Warnw("", "gossip validator", "reject") + return pubsub.ValidationReject + } + } + scheme, err := crypto.SchemeFromName(info.Scheme) + if err != nil { + c.log.Warnw("", "gossip validator", "reject", "err", err) + return pubsub.ValidationReject + } + + err = scheme.VerifyBeacon(rand, info.PublicKey) + if err != nil { + c.log.Warnw("", "gossip validator", "reject", "err", err) + return pubsub.ValidationReject + } + return pubsub.ValidationAccept + } +} diff --git a/client/lp2p/validator_test.go b/client/lp2p/validator_test.go new file mode 100644 index 0000000..0cebf36 --- /dev/null +++ b/client/lp2p/validator_test.go @@ -0,0 +1,271 @@ +package lp2p + +import ( + "context" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "google.golang.org/protobuf/proto" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/test/cache" + chain2 "github.com/drand/drand/common/chain" + dcrypto "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/test" + "github.com/drand/drand/internal/test/testlogger" + "github.com/drand/drand/protobuf/drand" +) + +type randomDataWrapper struct { + data client.RandomData +} + +func (r *randomDataWrapper) Round() uint64 { + return r.data.Rnd +} + +func (r *randomDataWrapper) Signature() []byte { + return r.data.Sig +} + +func (r *randomDataWrapper) Randomness() []byte { + return r.data.Random +} + +func randomPeerID(t *testing.T) peer.ID { + priv, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + peerID, err := peer.IDFromPrivateKey(priv) + if err != nil { + t.Fatal(err) + } + return peerID +} + +func fakeRandomData(info *chain2.Info, clk clock.Clock) client.RandomData { + rnd := chain.CurrentRound(clk.Now().Unix(), info.Period, info.GenesisTime) + + sig := make([]byte, 8) + binary.LittleEndian.PutUint64(sig, rnd) + psig := make([]byte, 8) + binary.LittleEndian.PutUint64(psig, rnd-1) + + return client.RandomData{ + Rnd: rnd, + Sig: sig, + PreviousSignature: psig, + Random: dcrypto.RandomnessFromSignature(sig), + } +} + +func fakeChainInfo() *chain2.Info { + return &chain2.Info{ + Period: time.Second, + GenesisTime: time.Now().Unix(), + PublicKey: test.GenerateIDs(1)[0].Public.Key, + } +} + +func TestRejectsUnmarshalBeaconFailure(t *testing.T) { + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(fakeChainInfo(), nil, &c, clk) + + msg := pubsub.Message{Message: &pb.Message{}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationReject { + t.Fatal(errors.New("expected reject for invalid message")) + } +} + +func TestAcceptsWithoutTrustRoot(t *testing.T) { + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(nil, nil, &c, clk) + + resp := drand.PublicRandResponse{} + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationAccept { + t.Fatal(errors.New("expected accept without trust root")) + } +} + +func TestRejectsFutureBeacons(t *testing.T) { + info := fakeChainInfo() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(info, nil, &c, clk) + + resp := drand.PublicRandResponse{ + Round: chain.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime) + 5, + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationReject { + t.Fatal(errors.New("expected reject for future message")) + } +} + +func TestRejectsVerifyBeaconFailure(t *testing.T) { + info := fakeChainInfo() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(info, nil, &c, clk) + + resp := drand.PublicRandResponse{ + Round: chain.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime), + // missing signature etc. + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationReject { + t.Fatal(errors.New("expected reject for beacon verification failure")) + } +} + +func TestIgnoresCachedEqualBeacon(t *testing.T) { + info := fakeChainInfo() + ca := cache.NewMapCache() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClockAt(time.Now()) + validate := randomnessValidator(info, ca, &c, clk) + rdata := fakeRandomData(info, clk) + + ca.Add(rdata.Rnd, &rdata) + + resp := drand.PublicRandResponse{ + Round: rdata.Rnd, + Signature: rdata.Sig, + PreviousSignature: rdata.PreviousSignature, + Randomness: rdata.Random, + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationIgnore { + t.Fatal(errors.New("expected ignore for cached beacon")) + } +} + +func TestRejectsCachedUnequalBeacon(t *testing.T) { + info := fakeChainInfo() + ca := cache.NewMapCache() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(info, ca, &c, clk) + rdata := fakeRandomData(info, clk) + + ca.Add(rdata.Rnd, &rdata) + + sig := make([]byte, 8) + binary.LittleEndian.PutUint64(sig, rdata.Rnd+1) + + resp := drand.PublicRandResponse{ + Round: rdata.Rnd, + Signature: rdata.Sig, + PreviousSignature: sig, // incoming message has incorrect previous sig + Randomness: rdata.Random, + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationReject { + t.Fatal(fmt.Errorf("expected reject for cached but unequal beacon, got: %v", res)) + } +} + +func TestIgnoresCachedEqualNonRandomDataBeacon(t *testing.T) { + info := fakeChainInfo() + ca := cache.NewMapCache() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClockAt(time.Now()) + validate := randomnessValidator(info, ca, &c, clk) + rdata := randomDataWrapper{fakeRandomData(info, clk)} + + ca.Add(rdata.Round(), &rdata) + + resp := drand.PublicRandResponse{ + Round: rdata.Round(), + Signature: rdata.Signature(), + PreviousSignature: rdata.data.PreviousSignature, + Randomness: rdata.Randomness(), + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationIgnore { + t.Fatal(errors.New("expected ignore for cached beacon")) + } +} + +func TestRejectsCachedEqualNonRandomDataBeacon(t *testing.T) { + info := fakeChainInfo() + ca := cache.NewMapCache() + c := Client{log: testlogger.New(t)} + clk := clock.NewFakeClock() + validate := randomnessValidator(info, ca, &c, clk) + rdata := randomDataWrapper{fakeRandomData(info, clk)} + + ca.Add(rdata.Round(), &rdata) + + sig := make([]byte, 8) + binary.LittleEndian.PutUint64(sig, rdata.Round()+1) + + resp := drand.PublicRandResponse{ + Round: rdata.Round(), + Signature: sig, // incoming message has incorrect sig + PreviousSignature: rdata.data.PreviousSignature, + Randomness: rdata.Randomness(), + } + data, err := proto.Marshal(&resp) + if err != nil { + t.Fatal(err) + } + msg := pubsub.Message{Message: &pb.Message{Data: data}} + res := validate(context.Background(), randomPeerID(t), &msg) + + if res != pubsub.ValidationReject { + t.Fatal(errors.New("expected reject for cached beacon")) + } +} diff --git a/client/metric.go b/client/metric.go new file mode 100644 index 0000000..254c070 --- /dev/null +++ b/client/metric.go @@ -0,0 +1,53 @@ +package client + +import ( + "context" + "time" + + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/metrics" +) + +func newWatchLatencyMetricClient(base client.Client, info *chain2.Info) client.Client { + ctx, cancel := context.WithCancel(context.Background()) + c := &watchLatencyMetricClient{ + Client: base, + chainInfo: info, + cancel: cancel, + } + go c.startObserve(ctx) + return c +} + +type watchLatencyMetricClient struct { + client.Client + chainInfo *chain2.Info + cancel context.CancelFunc +} + +func (c *watchLatencyMetricClient) startObserve(ctx context.Context) { + rch := c.Watch(ctx) + for { + select { + case result, ok := <-rch: + if !ok { + return + } + // compute the latency metric + actual := time.Now().UnixNano() + expected := chain.TimeOfRound(c.chainInfo.Period, c.chainInfo.GenesisTime, result.Round()) * 1e9 + // the labels of the gauge vec must already be set at the registerer level + metrics.ClientWatchLatency.Set(float64(actual-expected) / float64(time.Millisecond)) + case <-ctx.Done(): + return + } + } +} + +func (c *watchLatencyMetricClient) Close() error { + err := c.Client.Close() + c.cancel() + return err +} diff --git a/client/metric_test.go b/client/metric_test.go new file mode 100644 index 0000000..e2311ce --- /dev/null +++ b/client/metric_test.go @@ -0,0 +1,32 @@ +package client + +import ( + "sync" + "testing" + + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/common/client" +) + +func TestMetricClose(t *testing.T) { + chainInfo := fakeChainInfo(t) + wg := sync.WaitGroup{} + wg.Add(1) + + c := &clientMock.Client{ + WatchCh: make(chan client.Result), + CloseF: func() error { + wg.Done() + return nil + }, + } + + mc := newWatchLatencyMetricClient(c, chainInfo) + + err := mc.Close() // should close the underlying client + if err != nil { + t.Fatal(err) + } + + wg.Wait() // wait for underlying client to close +} diff --git a/client/mock/mock.go b/client/mock/mock.go new file mode 100644 index 0000000..4f1afd5 --- /dev/null +++ b/client/mock/mock.go @@ -0,0 +1,152 @@ +package mock + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/drand/drand/client/test/result/mock" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/chain" +) + +// Client provide a mocked client interface +// +//nolint:gocritic +type Client struct { + sync.Mutex + OptionalInfo *chain2.Info + WatchCh chan client.Result + WatchF func(context.Context) <-chan client.Result + Results []mock.Result + // Delay causes results to be delivered after this period of time has + // passed. Note that if the context is canceled a result is still consumed + // from Results. + Delay time.Duration + // CloseF is a function to call when the Close function is called on the + // mock client. + CloseF func() error + // if strict rounds is set, calls to get will scan through results to + // return the first result with the requested round, rather than simply + // popping the next result and treating it as a stack. + StrictRounds bool +} + +func (m *Client) String() string { + return "Mock" +} + +// Get returns a the randomness at `round` or an error. +func (m *Client) Get(ctx context.Context, round uint64) (client.Result, error) { + m.Lock() + if len(m.Results) == 0 { + m.Unlock() + return nil, errors.New("no result available") + } + r := m.Results[0] + if m.StrictRounds { + for _, candidate := range m.Results { + if candidate.Round() == round { + r = candidate + break + } + } + } else { + m.Results = m.Results[1:] + } + m.Unlock() + + if m.Delay > 0 { + t := time.NewTimer(m.Delay) + select { + case <-t.C: + case <-ctx.Done(): + return nil, ctx.Err() + } + } + + return &r, nil +} + +// Watch returns new randomness as it becomes available. +func (m *Client) Watch(ctx context.Context) <-chan client.Result { + if m.WatchCh != nil { + return m.WatchCh + } + if m.WatchF != nil { + return m.WatchF(ctx) + } + ch := make(chan client.Result, 1) + r, err := m.Get(ctx, 0) + if err == nil { + ch <- r + } + close(ch) + return ch +} + +func (m *Client) Info(_ context.Context) (*chain2.Info, error) { + if m.OptionalInfo != nil { + return m.OptionalInfo, nil + } + return nil, errors.New("not supported (mock client info)") +} + +// RoundAt will return the most recent round of randomness +func (m *Client) RoundAt(_ time.Time) uint64 { + return 0 +} + +// Close calls the optional CloseF function. +func (m *Client) Close() error { + if m.CloseF != nil { + return m.CloseF() + } + return nil +} + +// ClientWithResults returns a client on which `Get` works `m-n` times. +func ClientWithResults(n, m uint64) *Client { + c := new(Client) + for i := n; i < m; i++ { + c.Results = append(c.Results, mock.NewMockResult(i)) + } + return c +} + +// ClientWithInfo makes a client that returns the given info but no randomness +func ClientWithInfo(info *chain2.Info) client.Client { + return &InfoClient{info} +} + +type InfoClient struct { + i *chain2.Info +} + +func (m *InfoClient) String() string { + return "MockInfo" +} + +func (m *InfoClient) Info(_ context.Context) (*chain2.Info, error) { + return m.i, nil +} + +func (m *InfoClient) RoundAt(t time.Time) uint64 { + return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) +} + +func (m *InfoClient) Get(_ context.Context, _ uint64) (client.Result, error) { + return nil, errors.New("not supported (mock info client get)") +} + +func (m *InfoClient) Watch(_ context.Context) <-chan client.Result { + ch := make(chan client.Result, 1) + close(ch) + return ch +} + +func (m *InfoClient) Close() error { + return nil +} diff --git a/client/optimizing.go b/client/optimizing.go new file mode 100644 index 0000000..6fff80d --- /dev/null +++ b/client/optimizing.go @@ -0,0 +1,642 @@ +package client + +import ( + "context" + "errors" + "fmt" + "math" + "sort" + "strings" + "sync" + "time" + + "github.com/hashicorp/go-multierror" + + "github.com/drand/drand/common" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/chain" +) + +const ( + defaultRequestTimeout = time.Second * 5 + defaultSpeedTestInterval = time.Minute * 5 + // defaultRequestConcurrency controls both how many clients are raced + // when `Get` is called for on-demand results, and also how many watch + // clients are spun up (in addition to clients marked as passive) to + // provide results to `Watch` requests. + defaultRequestConcurrency = 1 + // defaultWatchRetryInterval is the time after which a closed watch channel + // is re-open when no context error occurred. + defaultWatchRetryInterval = time.Second * 30 + defaultChannelBuffer = 5 + + maxUnixTime = 1<<63 - 62135596801 + maxNanoSec = 999999999 +) + +type optimizingClient struct { + sync.RWMutex + clients []client.Client + passiveClients []client.Client + stats []*requestStat + requestTimeout time.Duration + requestConcurrency int + speedTestInterval time.Duration + watchRetryInterval time.Duration + log log.Logger + done chan struct{} +} + +// newOptimizingClient creates a drand client that measures the speed of clients +// and uses the fastest ones. +// +// Clients passed to the optimizing client are ordered by speed and calls to +// `Get` race the 2 fastest clients (by default) for the result. If a client +// errors then it is moved to the back of the list. +// +// A speed test is performed periodically in the background every 5 minutes (by +// default) to ensure we're still using the fastest clients. A negative speed +// test interval will disable testing. +// +// Calls to `Get` actually iterate over the speed-ordered client list with a +// concurrency of 2 (by default) until a result is retrieved. It means that the +// optimizing client will fallback to using the other slower clients in the +// event of failure(s). +// +// Additionally, calls to Get are given a timeout of 5 seconds (by default) to +// ensure no unbounded blocking occurs. +func newOptimizingClient( + l log.Logger, + clients []client.Client, + requestTimeout time.Duration, + requestConcurrency int, + speedTestInterval, + watchRetryInterval time.Duration, +) (*optimizingClient, error) { + if len(clients) == 0 { + return nil, errors.New("missing clients") + } + stats := make([]*requestStat, len(clients)) + now := time.Now() + for i, c := range clients { + stats[i] = &requestStat{client: c, rtt: 0, startTime: now} + } + done := make(chan struct{}) + if requestTimeout <= 0 { + requestTimeout = defaultRequestTimeout + } + if requestConcurrency <= 0 { + requestConcurrency = defaultRequestConcurrency + } + if speedTestInterval == 0 { + speedTestInterval = defaultSpeedTestInterval + } + if watchRetryInterval == 0 { + watchRetryInterval = defaultWatchRetryInterval + } + oc := &optimizingClient{ + clients: clients, + stats: stats, + requestTimeout: requestTimeout, + requestConcurrency: requestConcurrency, + speedTestInterval: speedTestInterval, + watchRetryInterval: watchRetryInterval, + log: l, + done: done, + } + return oc, nil +} + +// Start starts the background speed measurements of the optimizing client.Start +// SetLog should not be called after Start. +func (oc *optimizingClient) Start() { + if oc.speedTestInterval > 0 { + go oc.testSpeed() + } +} + +// MarkPassive tags a client as 'passive' - a generalization of the libp2p style gossip client. +// These clients will not participate in the speed test horse race, and will be protected from +// being stopped by the optimized watcher. +// Note: if a client marked as passive closes its results channel from a `watch` call, the +// optimizing client will not re-open it, as would be attempted with non-passive clients. +// MarkPassive must tag clients as passive before `Start` is run. +func (oc *optimizingClient) MarkPassive(c client.Client) { + oc.passiveClients = append(oc.passiveClients, c) + // push passive clients to the back of the list for `Get`s + for _, s := range oc.stats { + if s.client == c { + s.rtt = math.MaxInt64 + s.startTime = time.Unix(maxUnixTime, maxNanoSec) + } + } +} + +// String returns the name of this client. +func (oc *optimizingClient) String() string { + names := make([]string, len(oc.clients)) + for i, c := range oc.clients { + names[i] = fmt.Sprint(c) + } + return fmt.Sprintf("OptimizingClient(%s)", strings.Join(names, ", ")) +} + +type requestStat struct { + // client is the client used to make the request. + client client.Client + // rtt is the time it took to make the request. + rtt time.Duration + // startTime is the time at which the request was started. + startTime time.Time +} + +type requestResult struct { + // client is the client used to make the request. + client client.Client + // result is the return value from the call to Get. + result client.Result + // err is the error that occurred from a call to Get (not including context error). + err error + // stat is stats from the call to Get. + stat *requestStat +} + +// markedPassive checks if a client should be treated as passive +func (oc *optimizingClient) markedPassive(c client.Client) bool { + for _, p := range oc.passiveClients { + if p == c { + return true + } + } + return false +} + +func (oc *optimizingClient) testSpeed() { + clients := make([]client.Client, 0, len(oc.clients)) + for _, c := range oc.clients { + if !oc.markedPassive(c) { + clients = append(clients, c) + } + } + + for { + var stats []*requestStat + ctx, cancel := context.WithCancel(context.Background()) + ch := parallelGet(ctx, clients, 1, oc.requestTimeout, oc.requestConcurrency) + + LOOP: + for { + select { + case rr, ok := <-ch: + if !ok { + cancel() + break LOOP + } + if rr.err != nil { + oc.log.Infow("", "optimizing_client", "endpoint down when speed tested", "client", fmt.Sprintf("%s", rr.client), "err", rr.err) + } + stats = append(stats, rr.stat) + case <-oc.done: + cancel() + return + } + } + + oc.updateStats(stats) + + t := time.NewTimer(oc.speedTestInterval) + select { + case <-t.C: + case <-oc.done: + t.Stop() + return + } + } +} + +// SetLog configures the client log output. +func (oc *optimizingClient) SetLog(l log.Logger) { + oc.log = l +} + +// fastestClients returns a ordered slice of clients - fastest first. +func (oc *optimizingClient) fastestClients() []client.Client { + oc.RLock() + defer oc.RUnlock() + // copy the current ordered client list so we iterate over a stable slice + clients := make([]client.Client, 0, len(oc.stats)) + for _, s := range oc.stats { + clients = append(clients, s.client) + } + return clients +} + +// Get returns the randomness at `round` or an error. +func (oc *optimizingClient) Get(ctx context.Context, round uint64) (res client.Result, err error) { + clients := oc.fastestClients() + var stats []*requestStat + ch := raceGet(ctx, clients, round, oc.requestTimeout, oc.requestConcurrency) + err = errors.New("no valid clients") + +LOOP: + for { + select { + case rr, ok := <-ch: + if !ok { + break LOOP + } + stats = append(stats, rr.stat) + res = rr.result + if rr.err != nil && !errors.Is(rr.err, common.ErrEmptyClientUnsupportedGet) { + err = fmt.Errorf("%v - %w", err, rr.err) + } else if rr.err == nil { + err = nil + } + case <-ctx.Done(): + oc.updateStats(stats) + return nil, ctx.Err() + case <-oc.done: + oc.updateStats(stats) + return nil, errors.New("client closed") + } + } + + oc.updateStats(stats) + return res, err +} + +// get calls Get on the passed client and returns a requestResult or nil if the context was canceled. +func get(ctx context.Context, c client.Client, round uint64) *requestResult { + start := time.Now() + res, err := c.Get(ctx, round) + rtt := time.Since(start) + var stat requestStat + + // c failure, set a large RTT so it is sent to the back of the list + if err != nil && !errors.Is(err, ctx.Err()) { + stat = requestStat{c, math.MaxInt64, start} + return &requestResult{c, res, err, &stat} + } + + if ctx.Err() != nil { + return nil + } + + stat = requestStat{c, rtt, start} + return &requestResult{c, res, err, &stat} +} + +func raceGet(ctx context.Context, clients []client.Client, round uint64, timeout time.Duration, concurrency int) <-chan *requestResult { + results := make(chan *requestResult, len(clients)) + + go func() { + rctx, cancel := context.WithCancel(ctx) + defer cancel() + defer close(results) + ch := parallelGet(rctx, clients, round, timeout, concurrency) + + for { + select { + case rr, ok := <-ch: + if !ok { + return + } + results <- rr + if rr.err == nil { // race is won + return + } + case <-rctx.Done(): + return + } + } + }() + + return results +} + +func parallelGet(ctx context.Context, clients []client.Client, round uint64, timeout time.Duration, concurrency int) <-chan *requestResult { + results := make(chan *requestResult, len(clients)) + token := make(chan struct{}, concurrency) + + for i := 0; i < concurrency; i++ { + token <- struct{}{} + } + + go func() { + wg := sync.WaitGroup{} + LOOP: + for _, c := range clients { + c := c + select { + case <-token: + wg.Add(1) + go func(c client.Client) { + gctx, cancel := context.WithTimeout(ctx, timeout) + rr := get(gctx, c, round) + cancel() + if rr != nil { + results <- rr + } + token <- struct{}{} + wg.Done() + }(c) + case <-ctx.Done(): + break LOOP + } + } + wg.Wait() + close(results) + }() + + return results +} + +func (oc *optimizingClient) updateStats(stats []*requestStat) { + oc.Lock() + defer oc.Unlock() + + // update the round trip times with new samples + for _, next := range stats { + for _, curr := range oc.stats { + if curr.client == next.client { + if curr.startTime.Before(next.startTime) { + curr.rtt = next.rtt + curr.startTime = next.startTime + } + break + } + } + } + + // sort by fastest + sort.Slice(oc.stats, func(i, j int) bool { + return oc.stats[i].rtt < oc.stats[j].rtt + }) +} + +type watchResult struct { + client.Result + client.Client +} + +func (oc *optimizingClient) trackWatchResults(info *chain2.Info, in chan watchResult, out chan client.Result) { + defer close(out) + + latest := uint64(0) + for r := range in { + round := r.Result.Round() + timeOfRound := time.Unix(chain.TimeOfRound(info.Period, info.GenesisTime, round), 0) + stat := requestStat{ + client: r.Client, + rtt: time.Since(timeOfRound), + startTime: timeOfRound, + } + oc.updateStats([]*requestStat{&stat}) + if round > latest { + latest = round + out <- r.Result + } + } +} + +// Watch returns new randomness as it becomes available. +func (oc *optimizingClient) Watch(ctx context.Context) <-chan client.Result { + outChan := make(chan client.Result, defaultChannelBuffer) + inChan := make(chan watchResult, defaultChannelBuffer) + + info, err := oc.Info(ctx) + if err != nil { + oc.log.Errorw("", "optimizing_client", "failed to learn info", "err", err) + close(outChan) + return outChan + } + + state := watchState{ + ctx: ctx, + optimizer: oc, + active: make([]watchingClient, 0), + protected: make([]watchingClient, 0), + failed: make([]failedClient, 0), + retryInterval: oc.watchRetryInterval, + } + + closingClients := make(chan client.Client, 1) + for _, c := range oc.passiveClients { + c := c + go state.watchNext(ctx, c, inChan, closingClients) + state.protected = append(state.protected, watchingClient{c, nil}) + } + + go state.dispatchWatchingClients(inChan, closingClients) + go oc.trackWatchResults(info, inChan, outChan) + return outChan +} + +type watchingClient struct { + client.Client + context.CancelFunc +} + +type failedClient struct { + client.Client + backoffUntil time.Time +} + +type watchState struct { + ctx context.Context + optimizer *optimizingClient + active []watchingClient + protected []watchingClient + failed []failedClient + retryInterval time.Duration +} + +func (ws *watchState) dispatchWatchingClients(resultChan chan watchResult, closingClients chan client.Client) { + defer close(resultChan) + + // spin up initial watcher(s) + ws.tryRepopulate(resultChan, closingClients) + + ticker := time.NewTicker(ws.optimizer.watchRetryInterval) + defer ticker.Stop() + for { + select { + case c := <-closingClients: + // replace failed watchers + ws.done(c) + if ws.ctx.Err() == nil { + ws.tryRepopulate(resultChan, closingClients) + } + if len(ws.active) == 0 && len(ws.protected) == 0 { + return + } + case <-ticker.C: + // periodically cycle to fastest client. + clients := ws.optimizer.fastestClients() + if len(clients) == 0 { + continue + } + fastest := clients[0] + if ws.hasActive(fastest) == -1 && ws.hasProtected(fastest) == -1 { + ws.closeSlowest() + ws.tryRepopulate(resultChan, closingClients) + } + case <-ws.ctx.Done(): + // trigger client close. Will return once len(ws.active) == 0 + for _, c := range ws.active { + c.CancelFunc() + } + } + } +} + +func (ws *watchState) tryRepopulate(results chan watchResult, done chan client.Client) { + ws.clean() + + for { + if len(ws.active) >= ws.optimizer.requestConcurrency { + return + } + c := ws.nextUnwatched() + if c == nil { + return + } + cctx, cancel := context.WithCancel(ws.ctx) + + ws.active = append(ws.active, watchingClient{c, cancel}) + ws.optimizer.log.Infow("", "optimizing_client", "watching on client", "client", fmt.Sprintf("%s", c)) + go ws.watchNext(cctx, c, results, done) + } +} + +func (ws *watchState) watchNext(ctx context.Context, c client.Client, out chan watchResult, done chan client.Client) { + defer func() { done <- c }() + + resultStream := c.Watch(ctx) + for r := range resultStream { + out <- watchResult{r, c} + } + ws.optimizer.log.Infow("", "optimizing_client", "watch ended", "client", fmt.Sprintf("%s", c)) +} + +func (ws *watchState) clean() { + nf := make([]failedClient, 0, len(ws.failed)) + for _, f := range ws.failed { + if f.backoffUntil.After(time.Now()) { + nf = append(nf, f) + } + } + ws.failed = nf +} + +func (ws *watchState) close(clientIdx int) { + ws.active[clientIdx].CancelFunc() + ws.active[clientIdx] = ws.active[len(ws.active)-1] + ws.active[len(ws.active)-1] = watchingClient{} + ws.active = ws.active[:len(ws.active)-1] +} + +func (ws *watchState) done(c client.Client) { + idx := ws.hasActive(c) + if idx > -1 { + ws.close(idx) + ws.failed = append(ws.failed, failedClient{c, time.Now().Add(ws.retryInterval)}) + } else if i := ws.hasProtected(c); i > -1 { + ws.protected[i] = ws.protected[len(ws.protected)-1] + ws.protected = ws.protected[:len(ws.protected)-1] + return + } + // note: it's expected that the client may already not be active. + // this happens when the optimizing client has closed it via `closeSlowest` +} + +func (ws *watchState) hasActive(c client.Client) int { + for i, a := range ws.active { + if a.Client == c { + return i + } + } + return -1 +} + +func (ws *watchState) hasProtected(c client.Client) int { + for i, p := range ws.protected { + if p.Client == c { + return i + } + } + return -1 +} + +func (ws *watchState) closeSlowest() { + if len(ws.active) == 0 { + return + } + order := ws.optimizer.fastestClients() + idxs := make([]int, 0) + for _, c := range order { + if i := ws.hasActive(c); i > -1 { + idxs = append(idxs, i) + } + } + ws.close(idxs[len(idxs)-1]) +} + +func (ws *watchState) nextUnwatched() client.Client { + clients := ws.optimizer.fastestClients() +ClientLoop: + for _, c := range clients { + for _, a := range ws.active { + if c == a.Client { + continue ClientLoop + } + } + for _, f := range ws.failed { + if c == f.Client { + continue ClientLoop + } + } + for _, p := range ws.protected { + if c == p.Client { + continue ClientLoop + } + } + return c + } + return nil +} + +// Info returns the parameters of the chain this client is connected to. +// The public key, when it started, and how frequently it updates. +func (oc *optimizingClient) Info(ctx context.Context) (chainInfo *chain2.Info, err error) { + clients := oc.fastestClients() + for _, c := range clients { + ctx, cancel := context.WithTimeout(ctx, oc.requestTimeout) + chainInfo, err = c.Info(ctx) + cancel() + if err == nil { + break + } + } + return +} + +// RoundAt will return the most recent round of randomness that will be available +// at time for the current client. +func (oc *optimizingClient) RoundAt(t time.Time) uint64 { + return oc.clients[0].RoundAt(t) +} + +// Close stops the background speed tests and closes the client and it's +// underlying clients for further use. +func (oc *optimizingClient) Close() error { + var errs *multierror.Error + for _, c := range oc.clients { + errs = multierror.Append(errs, c.Close()) + } + close(oc.done) + + return errs.ErrorOrNil() +} diff --git a/client/optimizing_test.go b/client/optimizing_test.go new file mode 100644 index 0000000..67ef8d6 --- /dev/null +++ b/client/optimizing_test.go @@ -0,0 +1,317 @@ +package client + +import ( + "context" + "sync" + "testing" + "time" + + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/client" + "github.com/drand/drand/internal/test/testlogger" +) + +// waitForSpeedTest waits until all clients have had their initial speed test. +func waitForSpeedTest(t *testing.T, c client.Client, timeout time.Duration) { + t.Helper() + oc, ok := c.(*optimizingClient) + if !ok { + t.Fatal("client is not an optimizing client") + } + + timedOut := time.NewTimer(timeout) + defer timedOut.Stop() + for { + oc.RLock() + tested := true + for _, s := range oc.stats { + // all RTT's are zero until a speed test has been done + if s.rtt == 0 { + tested = false + break + } + } + oc.RUnlock() + + if tested { + return + } + + // try again in a bit... + zzz := time.NewTimer(time.Millisecond * 100) + select { + case <-zzz.C: + case <-timedOut.C: + zzz.Stop() + t.Fatal("timed out waiting for initial speed test to complete") + } + } +} + +func expectRound(t *testing.T, res client.Result, r uint64) { + t.Helper() + if res.Round() != r { + t.Fatalf("expected round %v, got %v", r, res.Round()) + } +} + +func closeClient(t *testing.T, c client.Client) { + t.Helper() + err := c.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestOptimizingGet(t *testing.T) { + c0 := clientMock.ClientWithResults(0, 5) + c1 := clientMock.ClientWithResults(5, 8) + + c0.Delay = time.Millisecond * 100 + c1.Delay = time.Millisecond + + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{c0, c1}, time.Second*5, 2, time.Minute*5, 0) + if err != nil { + t.Fatal(err) + } + oc.Start() + defer closeClient(t, oc) + + waitForSpeedTest(t, oc, 10*time.Second) + + // speed test will consume round 0 and 5 from c0 and c1 + // then c1 will be used because it's faster + expectRound(t, latestResult(t, oc), 6) // round 6 from c1 and round 1 from c0 (discarded) + expectRound(t, latestResult(t, oc), 7) // round 7 from c1 and round 2 from c0 (discarded) + expectRound(t, latestResult(t, oc), 3) // c1 error (no results left), round 3 from c0 + expectRound(t, latestResult(t, oc), 4) // round 4 from c0 +} + +func TestOptimizingWatch(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + c0 := clientMock.ClientWithResults(0, 5) + c1 := clientMock.ClientWithResults(5, 8) + c2 := clientMock.ClientWithInfo(fakeChainInfo(t)) + + wc1 := make(chan client.Result, 5) + c1.WatchCh = wc1 + + c0.Delay = time.Millisecond + + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{c0, c1, c2}, time.Second*5, 2, time.Minute*5, 0) + if err != nil { + t.Fatal(err) + } + oc.Start() + defer closeClient(t, oc) + + waitForSpeedTest(t, oc, time.Minute) + + ch := oc.Watch(ctx) + + expectRound(t, nextResult(t, ch), 1) // round 1 from c0 (after 100ms) + wc1 <- &mock.Result{Rnd: 2} + expectRound(t, nextResult(t, ch), 2) // round 2 from c1 and round 2 from c0 (discarded) + select { + case <-ch: + t.Fatal("should not get another watched result at this point") + case <-time.After(50 * time.Millisecond): + } + wc1 <- &mock.Result{Rnd: 6} + expectRound(t, nextResult(t, ch), 6) // round 6 from c1 +} + +func TestOptimizingWatchRetryOnClose(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var rnd uint64 + c := &clientMock.Client{ + // a single result for the speed test + Results: []mock.Result{mock.NewMockResult(0)}, + // return a watch channel that yields one result then closes + WatchF: func(context.Context) <-chan client.Result { + ch := make(chan client.Result, 1) + r := mock.NewMockResult(rnd) + rnd++ + ch <- &r + close(ch) + return ch + }, + } + + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{c}, 0, 0, 0, time.Millisecond) + if err != nil { + t.Fatal(err) + } + oc.Start() + defer closeClient(t, oc) + + waitForSpeedTest(t, oc, time.Minute) + + ch := oc.Watch(ctx) + + var i uint64 + for r := range ch { + if r.Round() != i { + t.Fatal("unexpected round number") + } + i++ + if i > 2 { + break + } + } +} + +func TestOptimizingWatchFailover(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + chainInfo := fakeChainInfo(t) + + var rndlk sync.Mutex + var rnd uint64 = 1 + wf := func(context.Context) <-chan client.Result { + rndlk.Lock() + defer rndlk.Unlock() + ch := make(chan client.Result, 1) + r := mock.NewMockResult(rnd) + rnd++ + if rnd < 5 { + ch <- &r + } + close(ch) + return ch + } + c1 := &clientMock.Client{ + Results: []mock.Result{mock.NewMockResult(0)}, + WatchF: wf, + } + c2 := &clientMock.Client{ + Results: []mock.Result{mock.NewMockResult(0)}, + WatchF: wf, + } + + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{clientMock.ClientWithInfo(chainInfo), c1, c2}, 0, 0, 0, time.Millisecond) + if err != nil { + t.Fatal(err) + } + oc.Start() + defer closeClient(t, oc) + + waitForSpeedTest(t, oc, time.Minute) + + ch := oc.Watch(ctx) + + var i uint64 = 1 + for r := range ch { + if r.Round() != i { + t.Fatalf("unexpected round number %d vs %d", r.Round(), i) + } + i++ + if i > 5 { + t.Fatal("there are a total of 4 rounds possible") + } + } + if i < 3 { + t.Fatalf("watching didn't flip / yield expected rounds. %d", i) + } +} + +func TestOptimizingRequiresClients(t *testing.T) { + lg := testlogger.New(t) + _, err := newOptimizingClient(lg, []client.Client{}, 0, 0, 0, 0) + if err == nil { + t.Fatal("expected err is nil but it shouldn't be") + } + if err.Error() != "missing clients" { + t.Fatal("unexpected error", err) + } +} + +func TestOptimizingIsLogging(t *testing.T) { + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) + if err != nil { + t.Fatal(err) + } + oc.SetLog(lg) +} + +func TestOptimizingIsCloser(t *testing.T) { + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) + if err != nil { + t.Fatal(err) + } + oc.Start() + err = oc.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestOptimizingInfo(t *testing.T) { + lg := testlogger.New(t) + chainInfo := fakeChainInfo(t) + oc, err := newOptimizingClient(lg, []client.Client{clientMock.ClientWithInfo(chainInfo)}, 0, 0, 0, 0) + if err != nil { + t.Fatal(err) + } + oc.Start() + i, err := oc.Info(context.Background()) + if err != nil { + t.Fatal(err) + } + if i != chainInfo { + t.Fatal("wrong chain info", i) + } +} + +func TestOptimizingRoundAt(t *testing.T) { + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) + if err != nil { + t.Fatal(err) + } + oc.Start() + r := oc.RoundAt(time.Now()) // mock client returns 0 always + if r != 0 { + t.Fatal("unexpected round", r) + } +} + +func TestOptimizingClose(t *testing.T) { + wg := sync.WaitGroup{} + + closeF := func() error { + wg.Done() + return nil + } + + clients := []client.Client{ + &clientMock.Client{WatchCh: make(chan client.Result), CloseF: closeF}, + &clientMock.Client{WatchCh: make(chan client.Result), CloseF: closeF}, + } + + wg.Add(len(clients)) + + lg := testlogger.New(t) + oc, err := newOptimizingClient(lg, clients, 0, 0, 0, 0) + if err != nil { + t.Fatal(err) + } + + err = oc.Close() // should close the underlying clients + if err != nil { + t.Fatal(err) + } + + wg.Wait() // wait for underlying clients to close +} diff --git a/client/poll.go b/client/poll.go new file mode 100644 index 0000000..b17be23 --- /dev/null +++ b/client/poll.go @@ -0,0 +1,64 @@ +package client + +import ( + "context" + "time" + + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/chain" +) + +// PollingWatcher generalizes the `Watch` interface for clients which learn new values +// by asking for them once each group period. +func PollingWatcher(ctx context.Context, c client.Client, chainInfo *chain2.Info, l log.Logger) <-chan client.Result { + ch := make(chan client.Result, 1) + r := c.RoundAt(time.Now()) + val, err := c.Get(ctx, r) + if err != nil { + l.Errorw("", "polling_client", "failed synchronous get", "from", c, "err", err) + close(ch) + return ch + } + ch <- val + + go func() { + defer close(ch) + + // Initially, wait to synchronize to the round boundary. + _, nextTime := chain.NextRound(time.Now().Unix(), chainInfo.Period, chainInfo.GenesisTime) + select { + case <-ctx.Done(): + return + case <-time.After(time.Duration(nextTime-time.Now().Unix()) * time.Second): + } + + r, err := c.Get(ctx, c.RoundAt(time.Now())) + if err == nil { + ch <- r + } else { + l.Errorw("", "polling_client", "failed first async get", "from", c, "err", err) + } + + // Then tick each period. + t := time.NewTicker(chainInfo.Period) + defer t.Stop() + for { + select { + case <-t.C: + r, err := c.Get(ctx, c.RoundAt(time.Now())) + if err == nil { + ch <- r + } else { + l.Errorw("", "polling_client", "failed subsequent watch poll", "from", c, "err", err) + } + // TODO: keep trying on errors? + case <-ctx.Done(): + return + } + } + }() + + return ch +} diff --git a/client/random.go b/client/random.go new file mode 100644 index 0000000..77cb521 --- /dev/null +++ b/client/random.go @@ -0,0 +1,25 @@ +package client + +// RandomData holds the full random response from the server, including data needed +// for validation. +type RandomData struct { + Rnd uint64 `json:"round,omitempty"` + Random []byte `json:"randomness,omitempty"` + Sig []byte `json:"signature,omitempty"` + PreviousSignature []byte `json:"previous_signature,omitempty"` +} + +// Round provides access to the round associated with this random data. +func (r *RandomData) Round() uint64 { + return r.Rnd +} + +// Signature provides the signature over this round's randomness +func (r *RandomData) Signature() []byte { + return r.Sig +} + +// Randomness exports the randomness +func (r *RandomData) Randomness() []byte { + return r.Random +} diff --git a/client/test/cache/cache.go b/client/test/cache/cache.go new file mode 100644 index 0000000..e2016c4 --- /dev/null +++ b/client/test/cache/cache.go @@ -0,0 +1,36 @@ +package cache + +import ( + "sync" + + "github.com/drand/drand/common/client" +) + +// MapCache is a simple cache that stores data in memory. +type MapCache struct { + sync.RWMutex + data map[uint64]client.Result +} + +// NewMapCache creates a new in memory cache backed by a map. +func NewMapCache() *MapCache { + return &MapCache{data: make(map[uint64]client.Result)} +} + +// TryGet provides a round beacon or nil if it is not cached. +func (mc *MapCache) TryGet(round uint64) client.Result { + mc.RLock() + defer mc.RUnlock() + r, ok := mc.data[round] + if !ok { + return nil + } + return r +} + +// Add adds an item to the cache +func (mc *MapCache) Add(round uint64, result client.Result) { + mc.Lock() + mc.data[round] = result + mc.Unlock() +} diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go new file mode 100644 index 0000000..64027b4 --- /dev/null +++ b/client/test/http/mock/httpserver.go @@ -0,0 +1,71 @@ +package mock + +import ( + "context" + "net" + "net/http" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + + chainCommon "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/core" + dhttp "github.com/drand/drand/internal/http" + "github.com/drand/drand/internal/test/mock" + "github.com/drand/drand/internal/test/testlogger" + "github.com/drand/drand/protobuf/drand" +) + +// NewMockHTTPPublicServer creates a mock drand HTTP server for testing. +func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chainCommon.Info, context.CancelFunc, func(bool)) { + t.Helper() + ctx := context.Background() + + server := mock.NewMockServer(t, badSecondRound, sch, clk) + client := core.Proxy(server) + + lg := testlogger.New(t) + lctx := log.ToContext(context.Background(), lg) + ctx, cancel := context.WithCancel(lctx) + + handler, err := dhttp.New(ctx, "") + if err != nil { + t.Fatal(err) + } + + var chainInfo *chainCommon.Info + for i := 0; i < 3; i++ { + protoInfo, err := server.ChainInfo(ctx, &drand.ChainInfoRequest{}) + if err != nil { + time.Sleep(10 * time.Millisecond) + continue + } + chainInfo, err = chainCommon.InfoFromProto(protoInfo) + if err != nil { + time.Sleep(10 * time.Millisecond) + continue + } + break + } + if chainInfo == nil { + t.Fatal("could not use server after 3 attempts.") + } + + handler.RegisterNewBeaconHandler(client, chainInfo.HashString()) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + httpServer := http.Server{Handler: handler.GetHTTPHandler(), ReadHeaderTimeout: 3 * time.Second} + go httpServer.Serve(listener) + + return listener.Addr().String(), chainInfo, func() { + httpServer.Shutdown(ctx) + cancel() + }, server.(mock.Service).EmitRand +} diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go new file mode 100644 index 0000000..c73bf21 --- /dev/null +++ b/client/test/result/mock/result.go @@ -0,0 +1,128 @@ +package mock + +import ( + "bytes" + "crypto/rand" + "crypto/sha256" + "encoding/binary" + "testing" + "time" + + "github.com/drand/drand/common/chain" + "github.com/drand/drand/crypto" + "github.com/drand/kyber/share" + "github.com/drand/kyber/sign/tbls" + "github.com/drand/kyber/util/random" +) + +// NewMockResult creates a mock result for testing. +func NewMockResult(round uint64) Result { + sig := make([]byte, 8) + binary.LittleEndian.PutUint64(sig, round) + return Result{ + Rnd: round, + Sig: sig, + Rand: crypto.RandomnessFromSignature(sig), + } +} + +// Result is a mock result that can be used for testing. +type Result struct { + Rnd uint64 + Rand []byte + Sig []byte + PSig []byte +} + +// Randomness is a hash of the signature. +func (r *Result) Randomness() []byte { + return r.Rand +} + +// Signature is the signature of the randomness for this round. +func (r *Result) Signature() []byte { + return r.Sig +} + +// PreviousSignature is the signature of the previous round. +func (r *Result) PreviousSignature() []byte { + return r.PSig +} + +// Round is the round number for this random data. +func (r *Result) Round() uint64 { + return r.Rnd +} + +// AssertValid checks that this result is valid. +func (r *Result) AssertValid(t *testing.T) { + t.Helper() + sigTarget := make([]byte, 8) + binary.LittleEndian.PutUint64(sigTarget, r.Rnd) + if !bytes.Equal(r.Sig, sigTarget) { + t.Fatalf("expected sig: %x, got %x", sigTarget, r.Sig) + } + randTarget := crypto.RandomnessFromSignature(sigTarget) + if !bytes.Equal(r.Rand, randTarget) { + t.Fatalf("expected rand: %x, got %x", randTarget, r.Rand) + } +} + +func sha256Hash(in []byte) []byte { + h := sha256.New() + h.Write(in) + return h.Sum(nil) +} + +func roundToBytes(r int) []byte { + var buff bytes.Buffer + binary.Write(&buff, binary.BigEndian, uint64(r)) + return buff.Bytes() +} + +// VerifiableResults creates a set of results that will pass a `chain.Verify` check. +func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { + secret := sch.KeyGroup.Scalar().Pick(random.New()) + public := sch.KeyGroup.Point().Mul(secret, nil) + previous := make([]byte, 32) + if _, err := rand.Reader.Read(previous); err != nil { + panic(err) + } + + out := make([]Result, count) + for i := range out { + + var msg []byte + if sch.Name == crypto.DefaultSchemeID { + msg = sha256Hash(append(previous[:], roundToBytes(i+1)...)) + } else { + msg = sha256Hash(roundToBytes(i + 1)) + } + + sshare := share.PriShare{I: 0, V: secret} + tsig, err := sch.ThresholdScheme.Sign(&sshare, msg) + if err != nil { + panic(err) + } + tshare := tbls.SigShare(tsig) + sig := tshare.Value() + + out[i] = Result{ + Sig: sig, + PSig: previous, + Rnd: uint64(i + 1), + Rand: crypto.RandomnessFromSignature(sig), + } + previous = make([]byte, len(sig)) + copy(previous[:], sig) + } + info := chain.Info{ + PublicKey: public, + Period: time.Second, + GenesisTime: time.Now().Unix() - int64(count), + GenesisSeed: out[0].PSig, + Scheme: sch.Name, + } + + return &info, out +} diff --git a/client/utils_test.go b/client/utils_test.go new file mode 100644 index 0000000..a7416e0 --- /dev/null +++ b/client/utils_test.go @@ -0,0 +1,65 @@ +package client + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test" +) + +// fakeChainInfo creates a chain info object for use in tests. +func fakeChainInfo(t *testing.T) *chain.Info { + t.Helper() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + return &chain.Info{ + Scheme: sch.Name, + Period: time.Second, + GenesisTime: time.Now().Unix(), + PublicKey: test.GenerateIDs(1)[0].Public.Key, + } +} + +func latestResult(t *testing.T, c client.Client) client.Result { + t.Helper() + r, err := c.Get(context.Background(), 0) + if err != nil { + t.Fatal("getting latest result", err) + } + return r +} + +// nextResult reads the next result from the channel and fails the test if it closes before a value is read. +func nextResult(t *testing.T, ch <-chan client.Result) client.Result { + t.Helper() + + select { + case r, ok := <-ch: + if !ok { + t.Fatal("closed before result") + } + return r + case <-time.After(time.Second): + t.Fatal("timed out waiting for result.") + return nil + } +} + +// compareResults asserts that two results are the same. +func compareResults(t *testing.T, a, b client.Result) { + t.Helper() + + if a.Round() != b.Round() { + t.Fatal("unexpected result round", a.Round(), b.Round()) + } + if !bytes.Equal(a.Randomness(), b.Randomness()) { + t.Fatal("unexpected result randomness", a.Randomness(), b.Randomness()) + } +} diff --git a/client/verify.go b/client/verify.go new file mode 100644 index 0000000..c1ea62f --- /dev/null +++ b/client/verify.go @@ -0,0 +1,206 @@ +package client + +import ( + "context" + "fmt" + "sync" + + "github.com/drand/drand/common" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" +) + +type verifyingClient struct { + // Client is the wrapped client. calls to `get` and `watch` return results proxied from this client's fetch + client.Client + + // indirectClient is used to fetch other rounds of randomness needed for verification. + // it is separated so that it can provide a cache or shared pool that the direct client may not. + indirectClient client.Client + + pointOfTrust client.Result + potLk sync.Mutex + strict bool + + scheme *crypto.Scheme + log log.Logger +} + +// newVerifyingClient wraps a client to perform `chain.Verify` on emitted results. +func newVerifyingClient(c client.Client, previousResult client.Result, strict bool, sch *crypto.Scheme) client.Client { + return &verifyingClient{ + Client: c, + indirectClient: c, + pointOfTrust: previousResult, + strict: strict, + scheme: sch, + log: log.DefaultLogger(), + } +} + +// SetLog configures the client log output. +func (v *verifyingClient) SetLog(l log.Logger) { + v.log = l.Named("verifyingClient") +} + +// Get returns a requested round of randomness +func (v *verifyingClient) Get(ctx context.Context, round uint64) (client.Result, error) { + info, err := v.indirectClient.Info(ctx) + if err != nil { + return nil, err + } + r, err := v.Client.Get(ctx, round) + if err != nil { + return nil, err + } + rd := asRandomData(r) + if err := v.verify(ctx, info, rd); err != nil { + return nil, err + } + return rd, nil +} + +// Watch returns new randomness as it becomes available. +func (v *verifyingClient) Watch(ctx context.Context) <-chan client.Result { + outCh := make(chan client.Result, 1) + + info, err := v.indirectClient.Info(ctx) + if err != nil { + v.log.Errorw("", "verifying_client", "could not get info", "err", err) + close(outCh) + return outCh + } + + inCh := v.Client.Watch(ctx) + go func() { + defer close(outCh) + for r := range inCh { + if err := v.verify(ctx, info, asRandomData(r)); err != nil { + v.log.Warnw("", "verifying_client", "skipping invalid watch round", "round", r.Round(), "err", err) + continue + } + outCh <- r + } + }() + return outCh +} + +type resultWithPreviousSignature interface { + PreviousSignature() []byte +} + +func asRandomData(r client.Result) *RandomData { + rd, ok := r.(*RandomData) + if ok { + return rd + } + rd = &RandomData{ + Rnd: r.Round(), + Random: r.Randomness(), + Sig: r.Signature(), + } + if rp, ok := r.(resultWithPreviousSignature); ok { + rd.PreviousSignature = rp.PreviousSignature() + } + + return rd +} + +func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round uint64) ([]byte, error) { + info, err := v.indirectClient.Info(ctx) + if err != nil { + v.log.Errorw("", "drand_client", "could not get info to verify round 1", "err", err) + return []byte{}, fmt.Errorf("could not get info: %w", err) + } + + if round == 1 { + return info.GenesisSeed, nil + } + + trustRound := uint64(1) + var trustPrevSig []byte + + v.potLk.Lock() + if v.pointOfTrust == nil || v.pointOfTrust.Round() > round { + // slow path + v.potLk.Unlock() + trustPrevSig, err = v.getTrustedPreviousSignature(ctx, 1) + if err != nil { + return nil, err + } + } else { + trustRound = v.pointOfTrust.Round() + trustPrevSig = v.pointOfTrust.Signature() + v.potLk.Unlock() + } + initialTrustRound := trustRound + + var next client.Result + for trustRound < round-1 { + trustRound++ + v.log.Warnw("", "verifying_client", "loading round to verify", "round", trustRound) + next, err = v.indirectClient.Get(ctx, trustRound) + if err != nil { + return []byte{}, fmt.Errorf("could not get round %d: %w", trustRound, err) + } + b := &common.Beacon{ + PreviousSig: trustPrevSig, + Round: trustRound, + Signature: next.Signature(), + } + + ipk := info.PublicKey.Clone() + + err = v.scheme.VerifyBeacon(b, ipk) + if err != nil { + v.log.Warnw("", "verifying_client", "failed to verify value", "b", b, "err", err) + return []byte{}, fmt.Errorf("verifying beacon: %w", err) + } + trustPrevSig = next.Signature() + } + if trustRound == round-1 && trustRound > initialTrustRound { + v.potLk.Lock() + v.pointOfTrust = next + v.potLk.Unlock() + } + + if trustRound != round-1 { + return []byte{}, fmt.Errorf("unexpected trust round %d", trustRound) + } + return trustPrevSig, nil +} + +func (v *verifyingClient) verify(ctx context.Context, info *chain2.Info, r *RandomData) (err error) { + fetchPrevSignature := v.strict // only useful for chained schemes + ps := r.PreviousSignature + + if fetchPrevSignature { + ps, err = v.getTrustedPreviousSignature(ctx, r.Round()) + if err != nil { + return + } + } + + b := &common.Beacon{ + PreviousSig: ps, // for unchained schemes, this is not used in the VerifyBeacon function and can be nil + Round: r.Round(), + Signature: r.Signature(), + } + + ipk := info.PublicKey.Clone() + + err = v.scheme.VerifyBeacon(b, ipk) + if err != nil { + return fmt.Errorf("verification of %v failed: %w", b, err) + } + + r.Random = crypto.RandomnessFromSignature(r.Sig) + return nil +} + +// String returns the name of this client. +func (v *verifyingClient) String() string { + return fmt.Sprintf("%s.(+verifier)", v.Client) +} diff --git a/client/verify_test.go b/client/verify_test.go new file mode 100644 index 0000000..5b6a0c9 --- /dev/null +++ b/client/verify_test.go @@ -0,0 +1,61 @@ +package client_test + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + client2 "github.com/drand/drand/client" + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test/testlogger" +) + +func mockClientWithVerifiableResults(ctx context.Context, t *testing.T, l log.Logger, n int) (client.Client, []mock.Result) { + t.Helper() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + + info, results := mock.VerifiableResults(n, sch) + mc := clientMock.Client{Results: results, StrictRounds: true, OptionalInfo: info} + + var c client.Client + + c, err = client2.Wrap( + ctx, + l, + []client.Client{clientMock.ClientWithInfo(info), &mc}, + client2.WithChainInfo(info), + client2.WithVerifiedResult(&results[0]), + client2.WithFullChainVerification(), + ) + require.NoError(t, err) + + return c, results +} + +func TestVerify(t *testing.T) { + VerifyFuncTest(t, 3, 1) +} + +func TestVerifyWithOldVerifiedResult(t *testing.T) { + VerifyFuncTest(t, 5, 4) +} + +func VerifyFuncTest(t *testing.T, clients, upTo int) { + ctx := context.Background() + l := testlogger.New(t) + c, results := mockClientWithVerifiableResults(ctx, t, l, clients) + + res, err := c.Get(context.Background(), results[upTo].Round()) + require.NoError(t, err) + + if res.Round() != results[upTo].Round() { + t.Fatal("expected to get result.", results[upTo].Round(), res.Round(), fmt.Sprintf("%v", c)) + } +} diff --git a/client/watcher.go b/client/watcher.go new file mode 100644 index 0000000..5ccf6bc --- /dev/null +++ b/client/watcher.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "io" + + "github.com/hashicorp/go-multierror" + + "github.com/drand/drand/common/client" +) + +type watcherClient struct { + client.Client + watcher Watcher +} + +func (c *watcherClient) Watch(ctx context.Context) <-chan client.Result { + return c.watcher.Watch(ctx) +} + +func (c *watcherClient) Close() error { + var errs *multierror.Error + cw, ok := c.watcher.(io.Closer) + if ok { + errs = multierror.Append(errs, cw.Close()) + } + errs = multierror.Append(errs, c.Client.Close()) + return errs.ErrorOrNil() +} + +// String returns the name of this client. +func (c *watcherClient) String() string { + return fmt.Sprintf("%s.(+watcher)", c.Client) +} diff --git a/client/watcher_test.go b/client/watcher_test.go new file mode 100644 index 0000000..bf7a629 --- /dev/null +++ b/client/watcher_test.go @@ -0,0 +1,86 @@ +package client + +import ( + "context" + "sync" + "testing" + "time" + + clientMock "github.com/drand/drand/client/mock" + "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand/common/client" +) + +func TestWatcherWatch(t *testing.T) { + results := []mock.Result{ + {Rnd: 1, Rand: []byte{1}}, + {Rnd: 2, Rand: []byte{2}}, + } + + ch := make(chan client.Result, len(results)) + for i := range results { + ch <- &results[i] + } + close(ch) + + w := watcherClient{nil, &clientMock.Client{WatchCh: ch}} + + i := 0 + for r := range w.Watch(context.Background()) { + compareResults(t, r, &results[i]) + i++ + } +} + +func TestWatcherGet(t *testing.T) { + results := []mock.Result{ + {Rnd: 1, Rand: []byte{1}}, + {Rnd: 2, Rand: []byte{2}}, + } + + cr := make([]mock.Result, len(results)) + copy(cr, results) + + c := &clientMock.Client{Results: cr} + + w := watcherClient{c, c} + + for i := range results { + r, err := w.Get(context.Background(), 0) + if err != nil { + t.Fatal(err) + } + compareResults(t, r, &results[i]) + } +} + +func TestWatcherRoundAt(t *testing.T) { + c := &clientMock.Client{} + + w := watcherClient{c, c} + + if w.RoundAt(time.Now()) != 0 { + t.Fatal("unexpected RoundAt value") + } +} + +func TestWatcherClose(t *testing.T) { + wg := sync.WaitGroup{} + wg.Add(2) + + closeF := func() error { + wg.Done() + return nil + } + + w := &clientMock.Client{CloseF: closeF} + c := &clientMock.Client{CloseF: closeF} + + wc := &watcherClient{c, w} + err := wc.Close() // should close the underlying client AND watcher + if err != nil { + t.Fatal(err) + } + + wg.Wait() // wait for underlying client AND watcher to close +} diff --git a/cmd/Dockerfile b/cmd/Dockerfile new file mode 100644 index 0000000..2258bbc --- /dev/null +++ b/cmd/Dockerfile @@ -0,0 +1,71 @@ +# build this dockerfile with context pointed at the root of the drand repo +FROM --platform=linux/amd64 golang:1.20.1-buster AS builder +MAINTAINER Hector Sanjuan + +ARG version=unknown + +ENV GOPATH /go +ENV SRC_PATH $GOPATH/src/github.com/drand/drand/ +ENV GOPROXY https://proxy.golang.org + +ENV SUEXEC_VERSION v0.2 +ENV TINI_VERSION v0.19.0 +RUN set -x \ + && cd /tmp \ + && git clone https://github.com/ncopa/su-exec.git \ + && cd su-exec \ + && git checkout -q $SUEXEC_VERSION \ + && make \ + && cd /tmp \ + && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ + && chmod +x tini + +# Get the TLS CA certificates, they're not provided by busybox. +RUN apt-get update && apt-get install -y ca-certificates + +COPY go.* $SRC_PATH +WORKDIR $SRC_PATH +RUN go mod download + +COPY . $SRC_PATH +RUN set -x && make build-client + +FROM --platform=linux/amd64 busybox:1-glibc +MAINTAINER Hector Sanjuan + +ENV GOPATH /go +ENV SRC_PATH /go/src/github.com/drand/drand +ENV DRAND_CLIENT_HOME /data/drand_client +# client command-line arguments +ENV DRAND_CLIENT_NETWORK "" +ENV DRAND_CLIENT_HASH "" +ENV DRAND_CLIENT_URL "" +ENV DRAND_CLIENT_RELAYS "" +ENV DRAND_CLIENT_PORT "42777" +ENV DRAND_CLIENT_METRICS_ADDRESS "0.0.0.0:32111" +ENV DRAND_CLIENT_METRICS_GATEWAY "" +ENV DRAND_CLIENT_METRICS_ID "" +ENV DRAND_CLIENT_METRICS_PUSH_INTERVAL 10 + +# expose peer host +EXPOSE 42777 + +# expose promethius API +EXPOSE 32111 + +COPY --from=builder $SRC_PATH/drand-client /usr/local/bin/drand-client +COPY --from=builder $SRC_PATH/cmd/client/entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --from=builder /tmp/su-exec/su-exec /sbin/su-exec +COPY --from=builder /tmp/tini /sbin/tini +COPY --from=builder /etc/ssl/certs /etc/ssl/certs + +RUN mkdir -p $DRAND_CLIENT_HOME && \ + addgroup -g 994 drand_client && \ + adduser -D -h $DRAND_CLIENT_HOME -u 996 -G drand_client drand_client && \ + chown drand_client:drand_client $DRAND_CLIENT_HOME + +VOLUME $DRAND_CLIENT_HOME +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/entrypoint.sh"] + +# Defaults for demo-client go here +CMD ["--watch", "--insecure"] diff --git a/cmd/entrypoint.sh b/cmd/entrypoint.sh new file mode 100644 index 0000000..7d11aa0 --- /dev/null +++ b/cmd/entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +set -e +user=drand_client + +if [ -n "$DOCKER_DEBUG" ]; then + set -x +fi + +if [ "$(id -u)" -eq 0 ]; then + echo "Changing user to $user" + # ensure directories are writable + su-exec "$user" test -w "${DRAND_CLIENT_HOME}" || chown -R -- "$user" "${DRAND_CLIENT_HOME}" + exec su-exec "$user" "$0" "$@" +fi + +exec drand-client \ + --url $DRAND_CLIENT_URL \ + --hash $DRAND_CLIENT_HASH \ + --relays $DRAND_CLIENT_RELAYS \ + --network $DRAND_CLIENT_NETWORK \ + --port $DRAND_CLIENT_PORT \ + --client-metrics-address $DRAND_CLIENT_METRICS_ADDRESS \ + --client-metrics-gateway $DRAND_CLIENT_METRICS_GATEWAY \ + --client-metrics-id $DRAND_CLIENT_METRICS_ID \ + --client-metrics-push-interval $DRAND_CLIENT_METRICS_PUSH_INTERVAL \ + $@ diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..e85f19a --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,209 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/prometheus/client_golang/prometheus/push" + "github.com/urfave/cli/v2" + + "github.com/drand/drand/client" + "github.com/drand/drand/common" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/lib" +) + +// Automatically set through -ldflags +// Example: go install -ldflags "-X main.buildDate=$(date -u +%d/%m/%Y@%H:%M:%S) -X main.gitCommit=$(git rev-parse HEAD)" +var ( + gitCommit = "none" + buildDate = "unknown" +) + +var watchFlag = &cli.BoolFlag{ + Name: "watch", + Usage: "stream new values as they become available", +} + +var roundFlag = &cli.IntFlag{ + Name: "round", + Usage: "request randomness for a specific round", +} + +var verboseFlag = &cli.BoolFlag{ + Name: "verbose", + Usage: "print debug-level log messages", + EnvVars: []string{"DRAND_CLIENT_VERBOSE"}, +} + +// client metric flags + +var clientMetricsAddressFlag = &cli.StringFlag{ + Name: "client-metrics-address", + Usage: "Server address for Prometheus metrics.", + Value: ":8080", + EnvVars: []string{"DRAND_CLIENT_METRICS"}, +} + +var clientMetricsGatewayFlag = &cli.StringFlag{ + Name: "client-metrics-gateway", + Usage: "Push gateway for Prometheus metrics.", + EnvVars: []string{"DRAND_CLIENT_METRICS_GATEWAY"}, +} + +var clientMetricsPushIntervalFlag = &cli.Int64Flag{ + Name: "client-metrics-push-interval", + Usage: "Push interval in seconds for Prometheus gateway.", + EnvVars: []string{"DRAND_CLIENT_METRICS_PUSH_INTERVAL"}, +} + +var clientMetricsIDFlag = &cli.StringFlag{ + Name: "client-metrics-id", + Usage: "Unique identifier for the client instance, used by the metrics system.", + EnvVars: []string{"DRAND_CLIENT_METRICS_ID"}, +} + +func main() { + version := common.GetAppVersion() + + lg := log.New(nil, log.DefaultLevel, false) + + app := cli.NewApp() + app.Name = "drand-client" + app.Version = version.String() + app.Usage = "CDN Drand client for loading randomness from an HTTP endpoint" + app.Flags = lib.ClientFlags + app.Flags = append(app.Flags, + watchFlag, roundFlag, + clientMetricsAddressFlag, clientMetricsGatewayFlag, clientMetricsIDFlag, + clientMetricsPushIntervalFlag, verboseFlag) + app.Action = func(c *cli.Context) error { + var level int + if c.Bool(verboseFlag.Name) { + level = log.DebugLevel + } else { + level = log.InfoLevel + } + + log.ConfigureDefaultLogger(os.Stderr, level, c.Bool(lib.JSONFlag.Name)) + if level != log.DefaultLevel { + lg = log.New(os.Stderr, level, c.Bool(lib.JSONFlag.Name)) + } + c.Context = log.ToContext(c.Context, lg) + + return Client(c) + } + + // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. + app.EnableBashCompletion = true + + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("drand client %s (date %v, commit %v)\n", version, buildDate, gitCommit) + } + + err := app.Run(os.Args) + if err != nil { + fmt.Printf("an error was found while executing the command. Err: [%s] \n", err) + os.Exit(1) + } +} + +// Client loads randomness from a server +func Client(c *cli.Context) error { + lg := log.FromContextOrDefault(c.Context) + + var opts []client.Option + + if c.IsSet(clientMetricsIDFlag.Name) { + clientID := c.String(clientMetricsIDFlag.Name) + if !c.IsSet(clientMetricsAddressFlag.Name) && !c.IsSet(clientMetricsGatewayFlag.Name) { + return fmt.Errorf("missing prometheus address or push gateway") + } + metricsAddr := c.String(clientMetricsAddressFlag.Name) + metricsGateway := c.String(clientMetricsGatewayFlag.Name) + metricsPushInterval := c.Int64(clientMetricsPushIntervalFlag.Name) + bridge := newPrometheusBridge(lg, metricsAddr, metricsGateway, metricsPushInterval) + bridgeWithID := client.WithPrometheus(prometheus.WrapRegistererWith( + prometheus.Labels{"client_id": clientID}, + bridge)) + opts = append(opts, bridgeWithID) + } + + apiClient, err := lib.Create(c, c.IsSet(clientMetricsIDFlag.Name), opts...) + if err != nil { + return err + } + + if c.IsSet(watchFlag.Name) { + return Watch(apiClient) + } + + round := uint64(0) + if c.IsSet(roundFlag.Name) { + round = uint64(c.Int(roundFlag.Name)) + } + rand, err := apiClient.Get(context.Background(), round) + if err != nil { + return err + } + fmt.Printf("%d\t%x\n", rand.Round(), rand.Randomness()) + return nil +} + +// Watch streams randomness from a client +func Watch(inst client.Watcher) error { + results := inst.Watch(context.Background()) + for r := range results { + fmt.Printf("%d\t%x\n", r.Round(), r.Randomness()) + } + return nil +} + +func newPrometheusBridge(l log.Logger, address, gateway string, pushIntervalSec int64) prometheus.Registerer { + b := &prometheusBridge{ + address: address, + pushIntervalSec: pushIntervalSec, + Registry: prometheus.NewRegistry(), + log: l, + } + if gateway != "" { + b.pusher = push.New(gateway, "drand_client_observations_push").Gatherer(b.Registry) + go b.pushLoop() + } + if address != "" { + http.Handle("/metrics", promhttp.HandlerFor(b.Registry, promhttp.HandlerOpts{ + Timeout: 10 * time.Second, + })) + go func() { + // http.ListenAndServe is marked as problematic + // because it does not have tweaked timeouts out of the box. + + //nolint + err := http.ListenAndServe(address, nil) + l.Fatalw("", "client", err) + }() + } + return b +} + +type prometheusBridge struct { + *prometheus.Registry + address string + pushIntervalSec int64 + pusher *push.Pusher + log log.Logger +} + +func (b *prometheusBridge) pushLoop() { + for { + time.Sleep(time.Second * time.Duration(b.pushIntervalSec)) + if err := b.pusher.Push(); err != nil { + b.log.Infow("", "client_metrics", "prometheus gateway push (%v)", err) + } + } +} diff --git a/internal/cli.go b/internal/cli.go new file mode 100644 index 0000000..6a04369 --- /dev/null +++ b/internal/cli.go @@ -0,0 +1,1316 @@ +// Package drand is a distributed randomness beacon. It provides periodically an +// unpredictable, bias-resistant, and verifiable random value. +package drand + +import ( + "bufio" + "bytes" + "context" + "errors" + "fmt" + "io" + gonet "net" + "os" + "path" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + + "github.com/BurntSushi/toml" + "github.com/urfave/cli/v2" + + "github.com/drand/drand/common" + "github.com/drand/drand/common/key" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/chain/boltdb" + "github.com/drand/drand/internal/core" + "github.com/drand/drand/internal/core/migration" + "github.com/drand/drand/internal/fs" + "github.com/drand/drand/internal/net" + common2 "github.com/drand/drand/protobuf/common" + "github.com/drand/drand/protobuf/drand" +) + +// Automatically set through -ldflags +// Example: go install -ldflags "-X main.buildDate=$(date -u +%d/%m/%Y@%H:%M:%S) -X main.gitCommit=$(git rev-parse HEAD)" +var ( + gitCommit = "none" + buildDate = "unknown" +) + +var SetVersionPrinter sync.Once + +const defaultPort = "8080" + +func banner(w io.Writer) { + version := common.GetAppVersion() + _, _ = fmt.Fprintf(w, "drand %s (date %v, commit %v)\n", version.String(), buildDate, gitCommit) +} + +var folderFlag = &cli.StringFlag{ + Name: "folder", + Value: core.DefaultConfigFolder(), + Usage: "Folder to keep all drand cryptographic information, with absolute path.", + EnvVars: []string{"DRAND_FOLDER"}, +} + +var verboseFlag = &cli.BoolFlag{ + Name: "verbose", + Usage: "If set, verbosity is at the debug level", + EnvVars: []string{"DRAND_VERBOSE"}, +} + +var tlsCertFlag = &cli.StringFlag{ + Name: "tls-cert", + Usage: "Set the TLS certificate chain (in PEM format) for this drand node. " + + "The certificates have to be specified as a list of whitespace-separated file paths. " + + "This parameter is required by default and can only be omitted if the --tls-disable flag is used.", + EnvVars: []string{"DRAND_TLS_CERT"}, +} + +var tlsKeyFlag = &cli.StringFlag{ + Name: "tls-key", + Usage: "Set the TLS private key (in PEM format) for this drand node. " + + "The key has to be specified as a file path. " + + "This parameter is required by default and can only be omitted if the --tls-disable flag is used.", + EnvVars: []string{"DRAND_TLS_KEY"}, +} + +var insecureFlag = &cli.BoolFlag{ + Name: "tls-disable", + Aliases: []string{"insecure"}, + Usage: "Disable TLS for all communications (not recommended).", + EnvVars: []string{"DRAND_TLS_DISABLE", "DRAND_INSECURE"}, +} + +var controlFlag = &cli.StringFlag{ + Name: "control", + Usage: "Set the port you want to listen to for control port commands. If not specified, we will use the default value.", + Value: "8888", + EnvVars: []string{"DRAND_CONTROL"}, +} + +var metricsFlag = &cli.StringFlag{ + Name: "metrics", + Usage: "Launch a metrics server at the specified (host:)port.", + 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.", + EnvVars: []string{"DRAND_PRIVATE_LISTEN"}, +} + +var pubListenFlag = &cli.StringFlag{ + Name: "public-listen", + Usage: "Set the listening (binding) address of the public API. Useful if you have some kind of proxy.", + EnvVars: []string{"DRAND_PUBLIC_LISTEN"}, +} + +var nodeFlag = &cli.StringFlag{ + Name: "nodes", + Usage: "Contact the nodes at the given list of whitespace-separated addresses which have to be present in group.toml.", + EnvVars: []string{"DRAND_NODES"}, +} + +var roundFlag = &cli.IntFlag{ + Name: "round", + Usage: "Request the public randomness generated at round num. If the drand beacon does not have the requested value," + + " it returns an error. If not specified, the current randomness is returned.", + EnvVars: []string{"DRAND_ROUND"}, +} + +var certsDirFlag = &cli.StringFlag{ + Name: "certs-dir", + Usage: "directory containing trusted certificates (PEM format). Useful for testing and self signed certificates", + EnvVars: []string{"DRAND_CERTS_DIR"}, +} + +var outFlag = &cli.StringFlag{ + Name: "out", + Usage: "save the group file into a separate file instead of stdout", + EnvVars: []string{"DRAND_OUT"}, +} + +var backupOutFlag = &cli.StringFlag{ + Name: "out", + Usage: "the filepath to save the backup to", +} + +var periodFlag = &cli.StringFlag{ + Name: "period", + Usage: "period to set when doing a setup", + EnvVars: []string{"DRAND_PERIOD"}, +} + +var catchupPeriodFlag = &cli.StringFlag{ + Name: "catchup-period", + Usage: "Minimum period while in catchup. Set only by the leader of share / reshares", + Value: "0s", + EnvVars: []string{"DRAND_CATCHUP_PERIOD"}, +} + +var thresholdFlag = &cli.IntFlag{ + Name: "threshold", + Usage: "threshold to use for the DKG", + EnvVars: []string{"DRAND_THRESHOLD"}, +} + +// TODO (dlsniper): This flag is a duplicate name of the nodeFlag. Should change the name. +var shareNodeFlag = &cli.IntFlag{ + Name: "nodes", + Usage: "number of nodes expected", + EnvVars: []string{"DRAND_NODES"}, +} + +var transitionFlag = &cli.BoolFlag{ + Name: "reshare", + Aliases: []string{"transition"}, + Usage: "When set, this flag indicates the share operation is a resharing. " + + "The node will use the currently stored group as the basis for the resharing", + EnvVars: []string{"DRAND_TRANSITION_FLAG"}, +} + +var forceFlag = &cli.BoolFlag{ + Name: "force", + Aliases: []string{"f"}, + Usage: "When set, this flag forces the daemon to start a new reshare operation. " + + "By default, it does not allow to restart one", + EnvVars: []string{"DRAND_FORCE"}, +} + +// secretFlag is the "manual" security when the "leader"/coordinator creates the +// group: every participant must know this secret. It is not a consensus, not +// perfect, but since all members are known after the protocol, and members can +// decide to redo the setup, it works in practice well enough. +// TODO Add a manual check when the group is created so the user manually ACK. +var secretFlag = &cli.StringFlag{ + Name: "secret-file", + Usage: "Specify the secret to use when doing the share so the leader knows you are an eligible potential participant." + + " must be at least 32 characters.", + EnvVars: []string{"DRAND_SECRET_FILE"}, +} + +var connectFlag = &cli.StringFlag{ + Name: "connect", + Usage: "Address of the coordinator that will assemble the public keys and start the DKG", + EnvVars: []string{"DRAND_CONNECT"}, +} + +var leaderFlag = &cli.BoolFlag{ + Name: "leader", + Usage: "Specify if this node should act as the leader for setting up the group", + EnvVars: []string{"DRAND_LEADER"}, +} + +var beaconOffset = &cli.IntFlag{ + Name: "beacon-delay", + Usage: "Leader uses this flag to specify the genesis time or transition time as a delay from when " + + " group is ready to run the share protocol", + EnvVars: []string{"DRAND_BEACON_DELAY"}, +} + +var oldGroupFlag = &cli.StringFlag{ + Name: "from", + Usage: "Old group.toml path to specify when a new node wishes to participate " + + "in a resharing protocol. This flag is optional in case a node is already" + + "included in the current DKG.", + EnvVars: []string{"DRAND_FROM"}, +} + +var proposalFlag = &cli.StringFlag{ + Name: "proposal", + Usage: "Path to a toml file specifying the leavers, joiners and remainers for a network proposal", + EnvVars: []string{"DRAND_PROPOSAL_PATH"}, +} + +var skipValidationFlag = &cli.BoolFlag{ + Name: "skipValidation", + Usage: "skips bls verification of beacon rounds for faster catchup.", + EnvVars: []string{"DRAND_SKIP_VALIDATION"}, +} + +var timeoutFlag = &cli.StringFlag{ + Name: "timeout", + Usage: fmt.Sprintf("Timeout to use during the DKG, in string format. Default is %s", core.DefaultDKGPhaseTimeout), + EnvVars: []string{"DRAND_TIMEOUT"}, +} + +var pushFlag = &cli.BoolFlag{ + Name: "push", + Usage: "Push mode forces the daemon to start making beacon requests to the other node, " + + "instead of waiting the other nodes contact it to catch-up on the round", + EnvVars: []string{"DRAND_PUSH"}, +} + +var sourceFlag = &cli.StringFlag{ + Name: "source", + Usage: "Source flag allows to provide an executable which output will be used as additional entropy during resharing step.", + EnvVars: []string{"DRAND_SOURCE"}, +} + +var userEntropyOnlyFlag = &cli.BoolFlag{ + Name: "user-source-only", + Usage: "user-source-only flag used with the source flag allows to only use the user's entropy to pick the dkg secret " + + "(won't be mixed with crypto/rand). Should be used for reproducibility and debbuging purposes.", + EnvVars: []string{"DRAND_USER_SOURCE_ONLY"}, +} + +var groupFlag = &cli.StringFlag{ + Name: "group", + Usage: "Test connections to nodes listed in the group", + EnvVars: []string{"DRAND_GROUP"}, +} + +var hashOnly = &cli.BoolFlag{ + Name: "hash", + Usage: "Only print the hash of the group file", + EnvVars: []string{"DRAND_HASH"}, +} + +var hashInfoReq = &cli.StringFlag{ + Name: "chain-hash", + Usage: "The hash of the chain info, used to validate integrity of the received group info", + Required: true, + EnvVars: []string{"DRAND_CHAIN_HASH"}, +} + +// TODO (DLSNIPER): This is a duplicate of the hashInfoReq. Should these be merged into a single flag? +var hashInfoNoReq = &cli.StringFlag{ + Name: "chain-hash", + Usage: "The hash of the chain info", + EnvVars: []string{"DRAND_CHAIN_HASH"}, +} + +// using a simple string flag because the StringSliceFlag is not intuitive +// see https://github.com/urfave/cli/issues/62 +var syncNodeFlag = &cli.StringFlag{ + Name: "sync-nodes", + Usage: ",<...> of (multiple) reachable drand daemon(s). " + + "When checking our local database, using our local daemon address will result in a dry run.", + Required: true, + EnvVars: []string{"DRAND_SYNC_NODES"}, +} + +var followFlag = &cli.BoolFlag{ + Name: "follow", + Usage: "Indicates whether we want to follow another daemon, if not we perform a check of our local DB. " + + "Requires to specify the chain-hash using the '" + hashInfoNoReq.Name + "' flag.", + EnvVars: []string{"DRAND_FOLLOW"}, +} + +var upToFlag = &cli.IntFlag{ + Name: "up-to", + Usage: "Specify a round at which the drand daemon will stop syncing the chain, " + + "typically used to bootstrap a new node in chained mode", + Value: 0, + EnvVars: []string{"DRAND_UP_TO"}, +} + +var schemeFlag = &cli.StringFlag{ + Name: "scheme", + Usage: "Indicates a set of values drand will use to configure the randomness generation process", + Value: crypto.DefaultSchemeID, + EnvVars: []string{"DRAND_SCHEME"}, +} + +var jsonFlag = &cli.BoolFlag{ + Name: "json", + Usage: "Set the output as json format", + EnvVars: []string{"DRAND_JSON"}, +} + +var beaconIDFlag = &cli.StringFlag{ + Name: "id", + Usage: "Indicates the id for the randomness generation process which will be started", + Value: "", + EnvVars: []string{"DRAND_ID"}, +} +var listIdsFlag = &cli.BoolFlag{ + Name: "list-ids", + Usage: "Indicates if it only have to list the running beacon ids instead of the statuses.", + Value: false, + EnvVars: []string{"DRAND_LIST_IDS"}, +} + +var allBeaconsFlag = &cli.BoolFlag{ + Name: "all", + Usage: "Indicates if we have to interact with all beacons chains", + Value: false, + EnvVars: []string{"DRAND_ALL"}, +} + +var storageTypeFlag = &cli.StringFlag{ + Name: "db", + Usage: "Which database engine to use. Supported values: bolt, postgres, or memdb.", + Value: "bolt", + EnvVars: []string{"DRAND_DB"}, +} + +var pgDSNFlag = &cli.StringFlag{ + Name: "pg-dsn", + Usage: "PostgreSQL DSN configuration.\n" + + "Supported options are:\n" + + //nolint:lll + "- sslmode: if the SSL connection is disabled or required. Default disabled. See: https://www.postgresql.org/docs/15/libpq-ssl.html#LIBPQ-SSL-PROTECTION\n" + + //nolint:lll + "- connect_timeout: how many seconds before the connection attempt times out. Default 5 (seconds). See: https://www.postgresql.org/docs/15/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT\n" + + "- max-idle: number of maximum idle connections. Default: 2\n" + + "- max-open: number of maximum open connections. Default: 0 - unlimited.\n", + + Value: "postgres://drand:drand@127.0.0.1:5432/drand?sslmode=disable&connect_timeout=5", + EnvVars: []string{"DRAND_PG_DSN"}, +} + +var memDBSizeFlag = &cli.IntFlag{ + Name: "memdb-size", + Usage: "The buffer size for in-memory storage. Must be at least 10. Recommended, 2000 or more", + Value: 2000, + EnvVars: []string{"DRAND_MEMDB_SIZE"}, +} + +var appCommands = []*cli.Command{ + dkgCommand, + { + Name: "start", + Usage: "Start the drand daemon.", + Flags: toArray(folderFlag, tlsCertFlag, tlsKeyFlag, + insecureFlag, controlFlag, privListenFlag, pubListenFlag, + metricsFlag, tracesFlag, tracesProbabilityFlag, + certsDirFlag, pushFlag, verboseFlag, oldGroupFlag, + skipValidationFlag, jsonFlag, beaconIDFlag, + storageTypeFlag, pgDSNFlag, memDBSizeFlag), + Action: func(c *cli.Context) error { + banner(c.App.Writer) + l := log.New(nil, logLevel(c), logJSON(c)). + Named("startCmd") + return startCmd(c, l) + }, + Before: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("runMigrationCmd") + return runMigration(c, l) + }, + }, + { + Name: "stop", + Usage: "Stop the drand daemon.\n", + Flags: toArray(controlFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + banner(c.App.Writer) + l := log.New(nil, logLevel(c), logJSON(c)). + Named("stopDaemon") + return stopDaemon(c, l) + }, + }, + { + Name: "share", + Usage: "Launch a sharing protocol.", + Flags: toArray(insecureFlag, controlFlag, oldGroupFlag, + timeoutFlag, sourceFlag, userEntropyOnlyFlag, secretFlag, + periodFlag, shareNodeFlag, thresholdFlag, connectFlag, outFlag, + leaderFlag, beaconOffset, transitionFlag, forceFlag, catchupPeriodFlag, + schemeFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + banner(c.App.Writer) + return deprecatedShareCommand(c) + }, + }, + { + Name: "load", + Usage: "Launch a sharing protocol from filesystem", + Flags: toArray(controlFlag, beaconIDFlag, insecureFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("loadCmd") + return loadCmd(c, l) + }, + }, + { + Name: "sync", + Usage: "sync your local randomness chain with other nodes and validate your local beacon chain. To follow a " + + "remote node, it requires the use of the '" + followFlag.Name + "' flag.", + Flags: toArray(folderFlag, controlFlag, hashInfoNoReq, syncNodeFlag, + tlsCertFlag, insecureFlag, upToFlag, beaconIDFlag, followFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("syncCmd") + return syncCmd(c, l) + }, + }, + { + Name: "generate-keypair", + Usage: "Generate the longterm keypair (drand.private, drand.public) " + + "for this node, and load it on the drand daemon if it is up and running.\n", + ArgsUsage: "
is the address other nodes will be able to contact this node on (specified as 'private-listen' to the daemon)", + Flags: toArray(controlFlag, folderFlag, insecureFlag, beaconIDFlag, schemeFlag), + Action: func(c *cli.Context) error { + banner(c.App.Writer) + l := log.New(nil, logLevel(c), logJSON(c)). + Named("generateKeyPairCmd") + + err := keygenCmd(c, l) + + // If keys were generated successfully, daemon needs to load them + // In other to load them, we run LoadBeacon cmd. + // + // TIP: If an error is found, it may indicate daemon is not running. If that is the case, keys will be loaded + // on drand startup. + if err == nil { + err2 := loadCmd(c, l) + if err2 != nil { + fmt.Fprintf(os.Stdout, "Keys couldn't be loaded on drand daemon. If it is not running, "+ + "these new keys will be loaded on startup. Err: %s\n", err2) + } + } + return err + }, + Before: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("generateKeyPairCmd") + return checkMigration(c, l) + }, + }, + + { + Name: "get", + Usage: "get allows for public information retrieval from a remote " + + "drand node.\n", + Subcommands: []*cli.Command{ + { + Name: "public", + Usage: "Get the latest public randomness from the drand " + + "beacon and verify it against the collective public key " + + "as specified in group.toml. Only one node is contacted by " + + "default. This command attempts to connect to the drand " + + "beacon via TLS and falls back to plaintext communication " + + "if the contacted node has not activated TLS in which case " + + "it prints a warning.\n", + Flags: toArray(tlsCertFlag, insecureFlag, roundFlag, nodeFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("getPublicRandomness") + return getPublicRandomness(c, l) + }, + }, + { + Name: "chain-info", + Usage: "Get the binding chain information that this node participates to", + ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.", + Flags: toArray(tlsCertFlag, insecureFlag, hashOnly, hashInfoNoReq), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("getChainInfo") + return getChainInfo(c, l) + }, + }, + }, + }, + { + Name: "util", + Usage: "Multiple commands of utility functions, such as reseting a state, checking the connection of a peer...", + Subcommands: []*cli.Command{ + { + Name: "check", + Usage: "Check node at the given `ADDRESS` (you can put multiple ones)" + + " in the group for accessibility over the gRPC communication. If the node " + + " is not running behind TLS, you need to pass the tls-disable flag. You can " + + "also check a whole group's connectivity with the group flag.", + Flags: toArray(groupFlag, certsDirFlag, insecureFlag, verboseFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("checkConnection") + return checkConnection(c, l) + }, + Before: checkArgs, + }, + { + Name: "remote-status", + Usage: "Ask for the statuses of remote nodes indicated by " + + "`ADDRESS1 ADDRESS2 ADDRESS3...`, including the network " + + "visibility over the rest of the addresses given.", + Flags: toArray(controlFlag, jsonFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("remoteStatusCmd") + return remoteStatusCmd(c, l) + }, + }, + { + Name: "ping", + Usage: "Pings the daemon checking its state\n", + Flags: toArray(controlFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("pingpongCmd") + return pingpongCmd(c, l) + }, + }, + { + Name: "list-schemes", + Usage: "List all scheme ids available to use\n", + Flags: toArray(controlFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("schemesCmd") + return schemesCmd(c, l) + }, + }, + { + Name: "status", + Usage: "Get the status of many modules of running the daemon\n", + Flags: toArray(controlFlag, jsonFlag, beaconIDFlag, allBeaconsFlag, listIdsFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("statusCmd") + return statusCmd(c, l) + }, + }, + { + Name: "migrate", + Usage: "Migrate folder structure to support multi-beacon drand. You DO NOT have to run it while drand is running.\n", + Flags: toArray(folderFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("migrateCmd") + return migrateCmd(c, l) + }, + Before: checkArgs, + }, + { + Name: "reset", + Usage: "Resets the local distributed information (share, group file and random beacons). It KEEPS the private/public key pair.", + Flags: toArray(folderFlag, controlFlag, beaconIDFlag, allBeaconsFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("resetCmd") + return resetCmd(c, l) + }, + Before: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("resetCmd") + return checkMigration(c, l) + }, + }, + { + Name: "del-beacon", + Usage: "Delete all beacons from the given `ROUND` number until the head of the chain. " + + " You MUST restart the daemon after that command.", + Flags: toArray(folderFlag, beaconIDFlag, allBeaconsFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("deleteBeaconCmd") + return deleteBeaconCmd(c, l) + }, + Before: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("deleteBeaconCmd") + return checkMigration(c, l) + }, + }, + { + Name: "self-sign", + Usage: "Signs the public identity of this node. Needed for backward compatibility with previous versions.", + Flags: toArray(folderFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("selfSignCmd") + return selfSign(c, l) + }, + Before: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("selfSignCmd") + return checkMigration(c, l) + }, + }, + { + Name: "backup", + Usage: "backs up the primary drand database to a secondary location.", + Flags: toArray(backupOutFlag, controlFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("backupDBCmd") + return backupDBCmd(c, l) + }, + }, + }, + }, + { + Name: "show", + Usage: "local information retrieval about the node's cryptographic " + + "material. Show prints the information about the collective " + + "public key (drand.cokey), the group details (group.toml)," + + "the long-term public key " + + "(drand.public), or the private key share (drand.share), " + + "respectively.\n", + Flags: toArray(folderFlag, controlFlag), + Subcommands: []*cli.Command{ + { + Name: "group", + Usage: "shows the current group.toml used. The group.toml " + + "may contain the distributed public key if the DKG has been " + + "ran already.\n", + Flags: toArray(outFlag, controlFlag, hashOnly, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("showGroupCmd") + return showGroupCmd(c, l) + }, + }, + { + Name: "chain-info", + Usage: "shows the chain information this node is participating to", + Flags: toArray(controlFlag, hashOnly, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("showChainInfoCmd") + return showChainInfo(c, l) + }, + }, + { + Name: "public", + Usage: "shows the long-term public key of a node.\n", + Flags: toArray(controlFlag, beaconIDFlag), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("showPublicCmd") + return showPublicCmd(c, l) + }, + }, + }, + }, +} + +// CLI runs the drand app +func CLI() *cli.App { + version := common.GetAppVersion() + + app := cli.NewApp() + app.Name = "drand" + + // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. + app.EnableBashCompletion = true + + SetVersionPrinter.Do(func() { + cli.VersionPrinter = func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "drand %s (date %v, commit %v)\n", version, buildDate, gitCommit) + } + }) + + app.ExitErrHandler = func(context *cli.Context, err error) { + // override to prevent default behavior of calling OS.exit(1), + // when tests expect to be able to run multiple commands. + } + app.Version = version.String() + app.Usage = "distributed randomness service" + // =====Commands===== + // we need to copy the underlying commands to avoid races, cli sadly doesn't support concurrent executions well + appComm := make([]*cli.Command, len(appCommands)) + for i, p := range appCommands { + if p == nil { + continue + } + v := *p + appComm[i] = &v + } + app.Commands = appComm + // we need to copy the underlying flags to avoid races + verbFlag := *verboseFlag + foldFlag := *folderFlag + app.Flags = toArray(&verbFlag, &foldFlag) + app.Before = testWindows + return app +} + +func resetCmd(c *cli.Context, l log.Logger) error { + conf := contextToConfig(c, l) + + fmt.Fprintf(c.App.Writer, "You are about to delete your local share, group file and generated random beacons. "+ + "Are you sure you wish to perform this operation? [y/N]") + reader := bufio.NewReader(c.App.Reader) + + answer, err := reader.ReadString('\n') + if err != nil { + return fmt.Errorf("error reading: %w", err) + } + + answer = strings.ToLower(strings.TrimSpace(answer)) + if answer != "y" { + fmt.Fprintf(c.App.Writer, "drand: not reseting the state.") + return nil + } + + stores, err := getKeyStores(c, l) + if err != nil { + fmt.Fprintf(c.App.Writer, "drand: err reading beacons database: %v\n", err) + os.Exit(1) + } + + for beaconID, store := range stores { + if err := store.Reset(); err != nil { + fmt.Fprintf(c.App.Writer, "drand: beacon id [%s] - err reseting key store: %v\n", beaconID, err) + os.Exit(1) + } + + if err := os.RemoveAll(path.Join(conf.ConfigFolderMB(), beaconID)); err != nil { + fmt.Fprintf(c.App.Writer, "drand: beacon id [%s] - err reseting beacons database: %v\n", beaconID, err) + os.Exit(1) + } + + fmt.Printf("drand: beacon id [%s] - database reset\n", beaconID) + } + + return nil +} + +func askPort(c *cli.Context) string { + for { + fmt.Fprintf(c.App.Writer, "No valid port given. Please, choose a port number (or ENTER for default port 8080): ") + + reader := bufio.NewReader(c.App.Reader) + input, err := reader.ReadString('\n') + if err != nil { + continue + } + + portStr := strings.TrimSpace(input) + if portStr == "" { + fmt.Fprintln(c.App.Writer, "Default port selected") + return defaultPort + } + + port, err := strconv.Atoi(portStr) + if err != nil || port < 1000 || port > 65536 { + continue + } + + return portStr + } +} + +func runMigration(c *cli.Context, l log.Logger) error { + if err := checkArgs(c); err != nil { + return err + } + + config := contextToConfig(c, l) + + return migration.MigrateSBFolderStructure(config.ConfigFolder()) +} + +func checkMigration(c *cli.Context, l log.Logger) error { + if err := checkArgs(c); err != nil { + return err + } + + config := contextToConfig(c, l) + + if isPresent := migration.CheckSBFolderStructure(config.ConfigFolder()); isPresent { + return fmt.Errorf("single-beacon drand folder structure was not migrated, " + + "please first do it with 'drand util migrate' command") + } + + if fs.CreateSecureFolder(config.ConfigFolderMB()) == "" { + return fmt.Errorf("something went wrong with the multi beacon folder. " + + "Make sure that you have the appropriate rights") + } + + return nil +} + +func testWindows(c *cli.Context) error { + // x509 not available on windows: must run without TLS + if runtime.GOOS == "windows" && !c.Bool(insecureFlag.Name) { + return errors.New("TLS is not available on Windows, please disable TLS") + } + return nil +} + +func keygenCmd(c *cli.Context, l log.Logger) error { + args := c.Args() + if !args.Present() { + return errors.New("missing drand address in argument. Abort") + } + + if args.Len() > 1 { + return fmt.Errorf("expecting only one argument, the address, but got:"+ + "\n\t%v\nAborting. Note that the flags need to go before the argument", args.Slice()) + } + + addr := args.First() + var validID = regexp.MustCompile(`:\d+$`) + if !validID.MatchString(addr) { + fmt.Println("Invalid port:", addr) + addr = addr + ":" + askPort(c) + } + + sch, err := crypto.SchemeFromName(c.String(schemeFlag.Name)) + if err != nil { + return err + } + + var priv *key.Pair + if c.Bool(insecureFlag.Name) { + fmt.Println("Generating private / public key pair without TLS.") + priv, err = key.NewKeyPair(addr, sch) + } else { + fmt.Println("Generating private / public key pair with TLS indication") + priv, err = key.NewTLSKeyPair(addr, sch) + } + if err != nil { + return err + } + + config := contextToConfig(c, l) + beaconID := getBeaconID(c) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + + if _, err := fileStore.LoadKeyPair(sch); err == nil { + keyDirectory := path.Join(config.ConfigFolderMB(), beaconID) + fmt.Fprintf(c.App.Writer, "Keypair already present in `%s`.\nRemove them before generating new one\n", keyDirectory) + return nil + } + if err := fileStore.SaveKeyPair(priv); err != nil { + return fmt.Errorf("could not save key: %w", err) + } + + fullpath := path.Join(config.ConfigFolderMB(), beaconID, key.FolderName) + absPath, err := filepath.Abs(fullpath) + + if err != nil { + return fmt.Errorf("err getting full path: %w", err) + } + fmt.Println("Generated keys at ", absPath) + + var buff bytes.Buffer + if err := toml.NewEncoder(&buff).Encode(priv.Public.TOML()); err != nil { + return err + } + + buff.WriteString("\n") + fmt.Println(buff.String()) + return nil +} + +func groupOut(c *cli.Context, group *key.Group) error { + if c.IsSet("out") { + groupPath := c.String("out") + if err := key.Save(groupPath, group, false); err != nil { + return fmt.Errorf("drand: can't save group to specified file name: %w", err) + } + } else if c.Bool(hashOnly.Name) { + fmt.Fprintf(c.App.Writer, "%x\n", group.Hash()) + } else { + var buff bytes.Buffer + if err := toml.NewEncoder(&buff).Encode(group.TOML()); err != nil { + return fmt.Errorf("drand: can't encode group to TOML: %w", err) + } + buff.WriteString("\n") + fmt.Fprintf(c.App.Writer, "The following group.toml file has been created\n") + fmt.Fprint(c.App.Writer, buff.String()) + fmt.Fprintf(c.App.Writer, "\nHash of the group configuration: %x\n", group.Hash()) + } + return nil +} + +func checkConnection(c *cli.Context, lg log.Logger) error { + var names []string + var beaconID string + + if c.IsSet(groupFlag.Name) { + if c.IsSet(beaconIDFlag.Name) { + return fmt.Errorf("id flag is not reqired when using group flag") + } + if err := testEmptyGroup(c.String(groupFlag.Name)); err != nil { + return err + } + group := new(key.Group) + if err := key.Load(c.String(groupFlag.Name), group); err != nil { + return fmt.Errorf("loading group failed: %w", err) + } + + for _, id := range group.Nodes { + names = append(names, id.Address()) + } + beaconID = common.GetCanonicalBeaconID(group.ID) + } else if c.Args().Present() { + for _, serverAddr := range c.Args().Slice() { + _, _, err := gonet.SplitHostPort(serverAddr) + if err != nil { + return fmt.Errorf("error for address %s: %w", serverAddr, err) + } + names = append(names, serverAddr) + } + beaconID = common.GetCanonicalBeaconID(c.String(beaconIDFlag.Name)) + } else { + return fmt.Errorf("drand: check-group expects a list of identities or %s flag", groupFlag.Name) + } + + conf := contextToConfig(c, lg) + isVerbose := c.IsSet(verboseFlag.Name) + allGood := true + isIdentityCheck := c.IsSet(groupFlag.Name) || c.IsSet(beaconIDFlag.Name) + invalidIds := make([]string, 0) + + for _, address := range names { + var err error + if isIdentityCheck { + err = checkIdentityAddress(lg, conf, address, !c.Bool(insecureFlag.Name), beaconID) + } else { + err = remotePingToNode(lg, address, !c.Bool(insecureFlag.Name)) + } + + if err != nil { + if isVerbose { + fmt.Fprintf(c.App.Writer, "drand: error checking id %s: %s\n", address, err) + } else { + fmt.Fprintf(c.App.Writer, "drand: error checking id %s\n", address) + } + allGood = false + invalidIds = append(invalidIds, address) + continue + } + fmt.Fprintf(c.App.Writer, "drand: id %s answers correctly\n", address) + } + if !allGood { + return fmt.Errorf("following nodes don't answer: %s", strings.Join(invalidIds, ",")) + } + return nil +} + +func checkIdentityAddress(lg log.Logger, conf *core.Config, addr string, tls bool, beaconID string) error { + peer := net.CreatePeer(addr, tls) + client := net.NewGrpcClientFromCertManager(lg, conf.Certs()) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + metadata := &common2.Metadata{BeaconID: beaconID} + identityResp, err := client.GetIdentity(ctx, peer, &drand.IdentityRequest{Metadata: metadata}) + if err != nil { + return err + } + + identity := &drand.Identity{ + Signature: identityResp.Signature, + Tls: identityResp.Tls, + Address: identityResp.Address, + Key: identityResp.Key, + } + sch, err := crypto.SchemeFromName(identityResp.SchemeName) + if err != nil { + lg.Errorw("received an invalid SchemeName in identity response", "received", identityResp.SchemeName) + return err + } + id, err := key.IdentityFromProto(identity, sch) + if err != nil { + return err + } + if id.Address() != addr { + return fmt.Errorf("mismatch of address: contact %s reply with %s", addr, id.Address()) + } + return nil +} + +// deleteBeaconCmd deletes all beacon in the database from the given round until +// 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) + if err != nil { + return fmt.Errorf("given round not valid: %d", sr) + } + + startRound := uint64(sr) + + stores, err := getDBStoresPaths(c, l) + if err != nil { + return err + } + + verbose := isVerbose(c) + + sch, err := crypto.GetSchemeFromEnv() + if err != nil { + return err + } + if sch.Name == crypto.DefaultSchemeID { + ctx = chain.SetPreviousRequiredOnContext(ctx) + } + + var er error + for beaconID, storePath := range stores { + if er != nil { + return er + } + // Using an anonymous function to not leak the defer + er = func() error { + store, err := boltdb.NewBoltStore(ctx, l, path.Join(storePath, core.DefaultDBFolder), conf.BoltOptions()) + if err != nil { + return fmt.Errorf("beacon id [%s] - invalid bolt store creation: %w", beaconID, err) + } + defer store.Close() + + lastBeacon, err := store.Last(ctx) + if err != nil { + return fmt.Errorf("beacon id [%s] - can't fetch last beacon: %w", beaconID, err) + } + if startRound > lastBeacon.Round { + 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) + } + + for round := startRound; round <= lastBeacon.Round; round++ { + err := store.Del(ctx, round) + if err != nil { + return fmt.Errorf("beacon id [%s] - error deleting round %d: %w", beaconID, round, err) + } + if verbose { + fmt.Printf("beacon id [%s] - deleted beacon round %d \n", beaconID, round) + } + } + return nil + }() + } + + return err +} + +func isVerbose(c *cli.Context) bool { + return c.IsSet(verboseFlag.Name) +} + +func logLevel(c *cli.Context) int { + if isVerbose(c) { + return log.DebugLevel + } + + return log.ErrorLevel +} + +func logJSON(c *cli.Context) bool { + return c.Bool(jsonFlag.Name) +} + +func toArray(flags ...cli.Flag) []cli.Flag { + return flags +} + +func getGroup(c *cli.Context) (*key.Group, error) { + g := &key.Group{} + groupPath := c.Args().First() + if err := testEmptyGroup(groupPath); err != nil { + return nil, err + } + if err := key.Load(groupPath, g); err != nil { + return nil, fmt.Errorf("drand: error loading group file: %w", err) + } + return g, nil +} + +func checkArgs(c *cli.Context) error { + 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") + } + } + if c.IsSet("certs-dir") { + _, err := fs.Files(c.String("certs-dir")) + if err != nil { + return err + } + } + + return nil +} + +func contextToConfig(c *cli.Context, l log.Logger) *core.Config { + var opts []core.ConfigOption + version := common.GetAppVersion() + + if c.IsSet(pubListenFlag.Name) { + opts = append(opts, core.WithPublicListenAddress(c.String(pubListenFlag.Name))) + } + if c.IsSet(privListenFlag.Name) { + opts = append(opts, core.WithPrivateListenAddress(c.String(privListenFlag.Name))) + } + + port := c.String(controlFlag.Name) + if port != "" { + opts = append(opts, core.WithControlPort(port)) + } + if c.IsSet(folderFlag.Name) { + opts = append(opts, core.WithConfigFolder(c.String(folderFlag.Name))) + } + opts = append(opts, core.WithVersion(fmt.Sprintf("drand/%s (%s)", version, gitCommit))) + + if c.Bool(insecureFlag.Name) { + opts = append(opts, core.WithInsecure()) + } else { + certPath, keyPath := c.String("tls-cert"), c.String("tls-key") + opts = append(opts, core.WithTLS(certPath, keyPath)) + } + if c.IsSet("certs-dir") { + paths, err := fs.Files(c.String("certs-dir")) + if err != nil { + // it wouldn't reach here, as it was verified on checkArgs func before + panic(err) + } + 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)) + case chain.PostgreSQL: + opts = append(opts, core.WithDBStorageEngine(chain.PostgreSQL)) + + if c.IsSet(pgDSNFlag.Name) { + pgdsn := c.String(pgDSNFlag.Name) + opts = append(opts, core.WithPgDSN(pgdsn)) + } + case chain.MemDB: + opts = append(opts, + core.WithDBStorageEngine(chain.MemDB), + core.WithMemDBSize(c.Int(memDBSizeFlag.Name)), + ) + default: + opts = append(opts, core.WithDBStorageEngine(chain.BoltDB)) + } + + conf := core.NewConfig(l, opts...) + return conf +} + +func getNodes(c *cli.Context) ([]*key.Node, error) { + group, err := getGroup(c) + if err != nil { + return nil, err + } + var ids []*key.Node + gids := group.Nodes + if c.IsSet("nodes") { + // search nodes listed on the flag in the group + for _, addr := range strings.Split(c.String("nodes"), ",") { + for _, gid := range gids { + if gid.Addr == addr { + ids = append(ids, gid) + } + } + } + if len(ids) == 0 { + return nil, errors.New("addresses specified don't exist in group.toml") + } + } else { + // select them all in order + ids = gids + } + if len(ids) == 0 { + return nil, errors.New("no nodes specified with --nodes are in the group file") + } + return ids, nil +} + +func testEmptyGroup(filePath string) error { + file, err := os.Open(filePath) + if err != nil { + return fmt.Errorf("can't open group path: %w", err) + } + defer file.Close() + fi, err := file.Stat() + if err != nil { + return fmt.Errorf("can't open file info: %w", err) + } + if fi.Size() == 0 { + return errors.New("group file empty") + } + return nil +} + +func getBeaconID(c *cli.Context) string { + return common.GetCanonicalBeaconID(c.String(beaconIDFlag.Name)) +} + +func getDBStoresPaths(c *cli.Context, l log.Logger) (map[string]string, error) { + conf := contextToConfig(c, l) + stores := make(map[string]string) + + if c.IsSet(allBeaconsFlag.Name) { + fi, err := os.ReadDir(conf.ConfigFolderMB()) + if err != nil { + return nil, fmt.Errorf("error trying to read stores from config folder: %w", err) + } + for _, f := range fi { + if f.IsDir() { + stores[f.Name()] = path.Join(conf.ConfigFolderMB(), f.Name()) + } + } + } else { + beaconID := getBeaconID(c) + + isPresent, err := fs.Exists(path.Join(conf.ConfigFolderMB(), beaconID)) + if err != nil || !isPresent { + return nil, fmt.Errorf("beacon id [%s] - error trying to read store: %w", beaconID, err) + } + + stores[beaconID] = path.Join(conf.ConfigFolderMB(), beaconID) + } + + return stores, nil +} + +func getKeyStores(c *cli.Context, l log.Logger) (map[string]key.Store, error) { + conf := contextToConfig(c, l) + + if c.IsSet(allBeaconsFlag.Name) { + return key.NewFileStores(conf.ConfigFolderMB()) + } + + beaconID := getBeaconID(c) + + store := key.NewFileStore(conf.ConfigFolderMB(), beaconID) + stores := map[string]key.Store{beaconID: store} + + return stores, nil +} + +func deprecatedShareCommand(_ *cli.Context) error { + return errors.New("the share command has been removed! Please use `drand dkg` instead") +} diff --git a/internal/cli_test.go b/internal/cli_test.go new file mode 100644 index 0000000..2954b8d --- /dev/null +++ b/internal/cli_test.go @@ -0,0 +1,1520 @@ +package drand + +import ( + "bytes" + "context" + "encoding/hex" + "errors" + "fmt" + gnet "net" + "os" + "os/exec" + "path" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "github.com/BurntSushi/toml" + "github.com/kabukky/httpscerts" + json "github.com/nikkolasg/hexjson" + "github.com/stretchr/testify/require" + + "github.com/drand/drand/common" + chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/key" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/chain/boltdb" + "github.com/drand/drand/internal/core" + dkg2 "github.com/drand/drand/internal/dkg" + "github.com/drand/drand/internal/fs" + "github.com/drand/drand/internal/net" + "github.com/drand/drand/internal/test" + "github.com/drand/drand/internal/test/testlogger" + "github.com/drand/kyber" + "github.com/drand/kyber/share" + "github.com/drand/kyber/share/dkg" + "github.com/drand/kyber/util/random" +) + +func TestMigrate(t *testing.T) { + tmp := getSBFolderStructure(t) + + args := []string{"drand", "util", "migrate", "--folder", tmp} + app := CLI() + require.NoError(t, app.Run(args)) + + l := testlogger.New(t) + config := core.NewConfig(l, core.WithConfigFolder(tmp)) + defaultBeaconPath := path.Join(config.ConfigFolderMB(), common.DefaultBeaconID) + + newGroupFilePath := path.Join(defaultBeaconPath, key.GroupFolderName) + newKeyFilePath := path.Join(defaultBeaconPath, key.FolderName) + newDBFilePath := path.Join(defaultBeaconPath, core.DefaultDBFolder) + + if !fs.FolderExists(defaultBeaconPath, newGroupFilePath) { + t.Errorf("group folder should have been migrated") + } + if !fs.FolderExists(defaultBeaconPath, newKeyFilePath) { + t.Errorf("key folder should have been migrated") + } + if !fs.FolderExists(defaultBeaconPath, newDBFilePath) { + t.Errorf("db folder should have been migrated") + } +} + +func TestResetError(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := getSBFolderStructure(t) + + args := []string{"drand", "util", "reset", "--folder", tmp, "--id", beaconID} + app := CLI() + require.Error(t, app.Run(args)) +} + +func TestDeleteBeaconError(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := getSBFolderStructure(t) + + // that command should delete round 3 and 4 + args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} + app := CLI() + require.Error(t, app.Run(args)) +} + +func TestDeleteBeacon(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + l := testlogger.New(t) + ctx := context.Background() + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + if sch.Name == crypto.DefaultSchemeID { + ctx = chain.SetPreviousRequiredOnContext(ctx) + } + tmp := path.Join(t.TempDir(), "drand") + + opt := core.WithConfigFolder(tmp) + conf := core.NewConfig(l, opt) + fs.CreateSecureFolder(conf.DBFolder(beaconID)) + store, err := boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) + require.NoError(t, err) + err = store.Put(ctx, &common.Beacon{ + Round: 1, + Signature: []byte("Hello"), + }) + require.NoError(t, err) + err = store.Put(ctx, &common.Beacon{ + Round: 2, + Signature: []byte("Hello"), + }) + require.NoError(t, err) + err = store.Put(ctx, &common.Beacon{ + Round: 3, + Signature: []byte("Hello"), + }) + require.NoError(t, err) + err = store.Put(ctx, &common.Beacon{ + Round: 4, + Signature: []byte("hello"), + }) + require.NoError(t, err) + // try to fetch round 3 and 4 + b, err := store.Get(ctx, 3) + require.NoError(t, err) + require.NotNil(t, b) + b, err = store.Get(ctx, 4) + require.NoError(t, err) + require.NotNil(t, b) + + err = store.Close() + require.NoError(t, err) + + args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} + app := CLI() + require.NoError(t, app.Run(args)) + + store, err = boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) + require.NoError(t, err) + + // try to fetch round 3 and 4 - it should now fail + _, err = store.Get(ctx, 3) + require.Error(t, err) + + _, err = store.Get(ctx, 4) + require.Error(t, err) +} + +func TestKeySelfSignError(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := getSBFolderStructure(t) + + args := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} + app := CLI() + require.Error(t, app.Run(args)) +} + +func TestKeySelfSign(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + l := testlogger.New(t) + + tmp := path.Join(t.TempDir(), "drand") + + args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} + require.NoError(t, CLI().Run(args)) + + selfSign := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} + // try self sign, it should only print that it's already the case + expectedOutput := "already self signed" + testCommand(t, selfSign, expectedOutput) + + // load, remove signature and save + config := core.NewConfig(l, core.WithConfigFolder(tmp)) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + + pair, err := fileStore.LoadKeyPair(nil) + require.NoError(t, err) + pair.Public.Signature = nil + require.NoError(t, fileStore.SaveKeyPair(pair)) + + expectedOutput = "identity self signed" + testCommand(t, selfSign, expectedOutput) +} + +func TestKeyGenError(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := getSBFolderStructure(t) + + args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} + app := CLI() + require.Error(t, app.Run(args)) +} + +func TestKeyGen(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + l := testlogger.New(t) + + tmp := path.Join(t.TempDir(), "drand") + sch, _ := crypto.GetSchemeFromEnv() + args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "--scheme", sch.Name, "127.0.0.1:8081"} + require.NoError(t, CLI().Run(args)) + + config := core.NewConfig(l, core.WithConfigFolder(tmp)) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + priv, err := fileStore.LoadKeyPair(nil) + require.NoError(t, err) + require.NotNil(t, priv.Public) + + tmp2 := path.Join(t.TempDir(), "drand2") + + args = []string{"drand", "generate-keypair", "--folder", tmp2, "--id", beaconID, "--scheme", sch.Name} + require.Error(t, CLI().Run(args)) + + config = core.NewConfig(l, core.WithConfigFolder(tmp2)) + fileStore = key.NewFileStore(config.ConfigFolderMB(), beaconID) + priv, err = fileStore.LoadKeyPair(nil) + require.Error(t, err) + require.Nil(t, priv) +} + +// tests valid commands and then invalid commands +func TestStartAndStop(t *testing.T) { + tmpPath := t.TempDir() + + n := 5 + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + _, group := test.BatchIdentities(n, sch, beaconID) + groupPath := path.Join(tmpPath, "group.toml") + require.NoError(t, key.Save(groupPath, group, false)) + + privateAddr := test.Addresses(1)[0] + + args := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmpPath, "--id", beaconID, privateAddr} + require.NoError(t, CLI().Run(args)) + + startCh := make(chan bool) + go func() { + startArgs := []string{"drand", "start", "--tls-disable", "--folder", tmpPath, "--private-listen", privateAddr} + // Allow the rest of the test to start + // Any error will be caught in the error check below + startCh <- true + err := CLI().Run(startArgs) + if err != nil { + t.Errorf("error starting the node %s\n", err) + t.Fail() + return + } + // After we finish the execution, flag that we finished. + // This allows the test to exit cleanly without reaching the + // timeout at the end. + startCh <- true + // TODO : figuring out how to not panic in grpc call + // ERROR: 2020/01/23 21:06:28 grpc: server failed to encode response: + // rpc error: code = Internal desc = grpc: error while marshaling: proto: + // Marshal called with nil + }() + <-startCh + time.Sleep(200 * time.Millisecond) + + stopArgs := []string{"drand", "stop"} + err = CLI().Run(stopArgs) + require.NoError(t, err) + + select { + case <-startCh: + case <-time.After(1 * time.Second): + t.Fatal("drand daemon did not stop") + } +} + +func TestUtilCheckReturnsErrorForPortNotMatchingKeypair(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + beaconID := test.GetBeaconIDFromEnv() + + tmp := t.TempDir() + + // try to generate a keypair and make it listen on another address + keyPort := test.FreePort() + keyAddr := "127.0.0.1:" + keyPort + generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} + require.NoError(t, CLI().Run(generate)) + + listenPort := test.FreePort() + listenAddr := "127.0.0.1:" + listenPort + listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", listenAddr, "--folder", tmp} + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + waitCh := make(chan bool) + go func() { + waitCh <- true + err := CLI().RunContext(ctx, listen) + if err != nil { + t.Errorf("error while starting the node %v\n", err) + t.Fail() + return + } + }() + <-waitCh + // TODO can we maybe try to bind continuously to not having to wait + time.Sleep(200 * time.Millisecond) + + // run the check tool it should fail because key and address are not + // consistent + check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, listenAddr} + require.Error(t, CLI().Run(check)) +} + +func TestUtilCheckSucceedsForPortMatchingKeypair(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := t.TempDir() + + keyPort := test.FreePort() + keyAddr := "127.0.0.1:" + keyPort + generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} + require.NoError(t, CLI().Run(generate)) + + listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", keyAddr, "--folder", tmp} + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + waitCh := make(chan bool) + go func() { + waitCh <- true + err := CLI().RunContext(ctx, listen) + if err != nil { + t.Errorf("error while starting the node %v\n", err) + t.Fail() + return + } + }() + <-waitCh + // TODO can we maybe try to bind continuously to not having to wait + time.Sleep(200 * time.Millisecond) + + check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, keyAddr} + require.NoError(t, CLI().Run(check)) +} + +//nolint:funlen +func TestStartWithoutGroup(t *testing.T) { + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + tmpPath := path.Join(t.TempDir(), "drand") + require.NoError(t, os.Mkdir(tmpPath, 0o740)) + + pubPath := path.Join(tmpPath, "pub.key") + port1, _ := strconv.Atoi(test.FreePort()) + addr := "127.0.0.1:" + strconv.Itoa(port1) + + ctrlPort1, ctrlPort2, metricsPort := test.FreePort(), test.FreePort(), test.FreePort() + + priv, err := key.NewKeyPair(addr, sch) + require.NoError(t, err) + require.NoError(t, key.Save(pubPath, priv.Public, false)) + + config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + require.NoError(t, fileStore.SaveKeyPair(priv)) + + startArgs := []string{ + "drand", + "start", + "--private-listen", priv.Public.Address(), + "--tls-disable", + "--verbose", + "--folder", tmpPath, + "--control", ctrlPort1, + "--metrics", "127.0.0.1:" + metricsPort, + } + + go func() { + err := CLI().Run(startArgs) + if err != nil { + t.Errorf(err.Error()) + } + }() + + time.Sleep(500 * time.Millisecond) + + t.Log("--- DRAND SHARE --- (expected to fail)") + // this must fail because not enough arguments + // TODO - test vectors testing on the inputs + + initDKGArgs := []string{"drand", "share", "--control", ctrlPort1, "--id", beaconID} + require.Error(t, CLI().Run(initDKGArgs)) + + t.Log("--- DRAND STOP --- (failing instance)") + err = CLI().Run([]string{"drand", "stop", "--control", ctrlPort1}) + require.NoError(t, err) + + t.Log(" --- DRAND GROUP ---") + + // fake group + _, group := test.BatchIdentities(5, sch, beaconID) + + // fake dkg output + fakeKey := sch.KeyGroup.Point().Pick(random.New()) + distKey := &key.DistPublic{ + Coefficients: []kyber.Point{ + fakeKey, + sch.KeyGroup.Point().Pick(random.New()), + sch.KeyGroup.Point().Pick(random.New()), + }, + } + priv.Public.TLS = false + + group.Period = 5 * time.Second + group.GenesisTime = time.Now().Unix() - 10 + group.PublicKey = distKey + group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} + group.Nodes[1] = &key.Node{Identity: priv.Public, Index: 1} + groupPath := path.Join(tmpPath, "drand_group.toml") + require.NoError(t, key.Save(groupPath, group, false)) + + // save it also to somewhere drand will find it + require.NoError(t, fileStore.SaveGroup(group)) + + // fake share + scalarOne := sch.KeyGroup.Scalar().One() + s := &share.PriShare{I: 2, V: scalarOne} + fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} + require.NoError(t, fileStore.SaveShare(fakeShare)) + + // save a fake complete DKG in the store + dStore, err := dkg2.NewDKGStore(tmpPath, nil) + require.NoError(t, err) + err = dStore.SaveFinished(beaconID, &dkg2.DBState{ + BeaconID: beaconID, + Epoch: 1, + State: dkg2.Complete, + Threshold: 1, + Timeout: time.Unix(2549084715, 0).UTC(), // this will need updated in 2050 :^) + SchemeID: sch.Name, + GenesisTime: time.Unix(1669718523, 0).UTC(), + GenesisSeed: []byte("deadbeef"), + TransitionTime: time.Unix(1669718523, 0).UTC(), + CatchupPeriod: 5 * time.Second, + BeaconPeriod: 10 * time.Second, + + Leader: nil, + Remaining: nil, + Joining: nil, + Leaving: nil, + + Acceptors: nil, + Rejectors: nil, + + FinalGroup: group, + KeyShare: fakeShare, + }) + require.NoError(t, err) + + // Have to close it afterwards or starting the node will become unresponsive + err = dStore.Close() + require.NoError(t, err) + + t.Logf(" --- DRAND START --- control %s\n", ctrlPort2) + + start2 := []string{ + "drand", + "start", + "--control", ctrlPort2, + "--private-listen", priv.Public.Address(), + "--tls-disable", + "--folder", tmpPath, + "--verbose", + } + + go func() { + err := CLI().Run(start2) + if err != nil { + t.Errorf("error while starting second node: %v", err) + } + }() + + stop2 := []string{"drand", "stop", "--control", ctrlPort2} + defer func() { + err := CLI().Run(stop2) + if err != nil { + t.Errorf("error while stopping second node: %v", err) + } + }() + + time.Sleep(500 * time.Millisecond) + + testStartedDrandFunctional(t, ctrlPort2, tmpPath, priv.Public.Address(), group, fileStore, beaconID) +} + +func testStartedDrandFunctional(t *testing.T, ctrlPort, rootPath, address string, group *key.Group, fileStore key.Store, beaconID string) { + t.Helper() + lg := testlogger.New(t) + + testPing(t, ctrlPort) + testStatus(t, ctrlPort, beaconID) + testListSchemes(t, ctrlPort) + + require.NoError(t, toml.NewEncoder(os.Stdout).Encode(group.TOML())) + + t.Log("Running CHAIN-INFO command") + chainInfo, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") + require.NoError(t, err) + expectedOutput := string(chainInfo) + chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-disable", address} + testCommand(t, chainInfoCmd, expectedOutput) + + t.Log("Running CHAIN-INFO --HASH command") + chainInfoCmdHash := []string{"drand", "get", "chain-info", "--hash", "--tls-disable", address} + expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) + testCommand(t, chainInfoCmdHash, expectedOutput) + + showChainInfo := []string{"drand", "show", "chain-info", "--control", ctrlPort} + buffCi, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") + require.NoError(t, err) + testCommand(t, showChainInfo, string(buffCi)) + + showChainInfo = []string{"drand", "show", "chain-info", "--hash", "--control", ctrlPort} + expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) + testCommand(t, showChainInfo, expectedOutput) + + // reset state + resetCmd := []string{"drand", "util", "reset", "--folder", rootPath, "--id", beaconID} + r, w, err := os.Pipe() + require.NoError(t, err) + _, err = w.WriteString("y\n") + require.NoError(t, err) + os.Stdin = r + require.NoError(t, CLI().Run(resetCmd)) + _, err = fileStore.LoadShare(nil) + require.Error(t, err) + _, err = fileStore.LoadGroup() + require.Error(t, err) +} + +func testPing(t *testing.T, ctrlPort string) { + t.Helper() + + var err error + + t.Logf(" + running PING command with %s\n", ctrlPort) + for i := 0; i < 3; i++ { + ping := []string{"drand", "util", "ping", "--control", ctrlPort} + err = CLI().Run(ping) + if err == nil { + break + } + time.Sleep(500 * time.Millisecond) + } + require.NoError(t, err) +} + +func testStatus(t *testing.T, ctrlPort, beaconID string) { + t.Helper() + + var err error + + t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) + for i := 0; i < 3; i++ { + status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} + err = CLI().Run(status) + if err == nil { + return + } + time.Sleep(500 * time.Millisecond) + } + require.NoError(t, err) +} + +func testFailStatus(t *testing.T, ctrlPort, beaconID string) { + t.Helper() + + var err error + + t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) + for i := 0; i < 3; i++ { + status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} + err = CLI().Run(status) + require.Error(t, err) + time.Sleep(500 * time.Millisecond) + } +} + +func testListSchemes(t *testing.T, ctrlPort string) { + t.Helper() + + var err error + + t.Logf(" + running list schemes command with %s\n", ctrlPort) + for i := 0; i < 3; i++ { + schemes := []string{"drand", "util", "list-schemes", "--control", ctrlPort} + err = CLI().Run(schemes) + if err == nil { + break + } + time.Sleep(500 * time.Millisecond) + } + require.NoError(t, err) +} + +//nolint:funlen //This is a test +func TestClientTLS(t *testing.T) { + t.Skip("The test fails because the logic for generating the group has changed") + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + tmpPath := path.Join(t.TempDir(), "drand") + require.NoError(t, os.Mkdir(tmpPath, 0o740)) + + groupPath := path.Join(tmpPath, "group.toml") + certPath := path.Join(tmpPath, "server.pem") + keyPath := path.Join(tmpPath, "key.pem") + pubPath := path.Join(tmpPath, "pub.key") + + freePort := test.FreePort() + addr := "127.0.0.1:" + freePort + ctrlPort := test.FreePort() + metricsPort := test.FreePort() + + priv, err := key.NewTLSKeyPair(addr, nil) + require.NoError(t, err) + require.NoError(t, key.Save(pubPath, priv.Public, false)) + + config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + err = fileStore.SaveKeyPair(priv) + require.NoError(t, err) + + if httpscerts.Check(certPath, keyPath) != nil { + t.Log("generating on the fly") + h, _, err := gnet.SplitHostPort(priv.Public.Address()) + require.NoError(t, err) + err = httpscerts.Generate(certPath, keyPath, h) + require.NoError(t, err) + } + + // fake group + _, group := test.BatchTLSIdentities(5, sch, beaconID) + // fake dkg outuput + fakeKey := sch.KeyGroup.Point().Pick(random.New()) + // need a threshold of coefficients + distKey := &key.DistPublic{ + Coefficients: []kyber.Point{ + fakeKey, + sch.KeyGroup.Point().Pick(random.New()), + sch.KeyGroup.Point().Pick(random.New()), + }, + } + group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} + group.Period = 2 * time.Minute + group.GenesisTime = time.Now().Unix() + group.PublicKey = distKey + require.NoError(t, fileStore.SaveGroup(group)) + require.NoError(t, key.Save(groupPath, group, false)) + + // fake share + scalarOne := sch.KeyGroup.Scalar().One() + s := &share.PriShare{I: 2, V: scalarOne} + // TODO: check DistKeyShare if it needs a scheme + fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} + err = fileStore.SaveShare(fakeShare) + require.NoError(t, err) + + startArgs := []string{ + "drand", + "start", + "--private-listen", priv.Public.Address(), + "--tls-cert", certPath, + "--tls-key", keyPath, + "--control", ctrlPort, + "--folder", tmpPath, + "--metrics", metricsPort, + } + go func() { + err := CLI().Run(startArgs) + if err != nil { + t.Errorf("error while starting node: %v", err) + } + }() + + stopArgs := []string{"drand", "stop", "--control", ctrlPort} + defer func() { + err := CLI().Run(stopArgs) + if err != nil { + t.Errorf("error while stopping the node: %v", err) + } + }() + + time.Sleep(500 * time.Millisecond) + + testStartedTLSDrandFunctional(t, ctrlPort, certPath, group, priv) +} + +func testStartedTLSDrandFunctional(t *testing.T, ctrlPort, certPath string, group *key.Group, priv *key.Pair) { + t.Helper() + lg := testlogger.New(t) + + var err error + + chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-cert", certPath, priv.Public.Address()} + chainInfoBuff, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") + require.NoError(t, err) + expectedOutput := string(chainInfoBuff) + testCommand(t, chainInfoCmd, expectedOutput) + + showPublic := []string{"drand", "show", "public", "--control", ctrlPort} + b, _ := priv.Public.Key.MarshalBinary() + exp := hex.EncodeToString(b) + testCommand(t, showPublic, exp) + + showCokey := []string{"drand", "show", "chain-info", "--control", ctrlPort} + expectedOutput = string(chainInfoBuff) + testCommand(t, showCokey, expectedOutput) + + showGroup := []string{"drand", "show", "group", "--control", ctrlPort} + testCommand(t, showGroup, "") + + showHash := []string{"drand", "show", "group", "--control", ctrlPort, "--hash"} + groupHash := hex.EncodeToString(group.Hash()) + testCommand(t, showHash, groupHash) +} + +func testCommand(t *testing.T, args []string, exp string) { + t.Helper() + + var buff bytes.Buffer + t.Log("--------------") + cli := CLI() + cli.Writer = &buff + require.NoError(t, cli.Run(args)) + if exp == "" { + return + } + t.Logf("RUNNING: %v\n", args) + require.Contains(t, strings.Trim(buff.String(), "\n"), exp) +} + +// getSBFolderStructure create a new single-beacon folder structure in a temporary folder +func getSBFolderStructure(t *testing.T) string { + t.Helper() + + tmp := path.Join(t.TempDir(), "drand") + + fs.CreateSecureFolder(path.Join(tmp, key.GroupFolderName)) + fs.CreateSecureFolder(path.Join(tmp, key.FolderName)) + fs.CreateSecureFolder(path.Join(tmp, core.DefaultDBFolder)) + + return tmp +} + +func TestDrandListSchemes(t *testing.T) { + n := 2 + instances := genAndLaunchDrandInstances(t, n) + + for _, instance := range instances { + remote := []string{"drand", "util", "list-schemes", "--control", instance.ctrlPort} + + err := CLI().Run(remote) + require.NoError(t, err) + } +} + +func TestDrandReloadBeacon(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + n := 4 + instances := genAndLaunchDrandInstances(t, n) + + for i, inst := range instances { + if i == 0 { + inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) + } else { + inst.join(t, beaconID) + } + } + instances[0].executeDKG(t, beaconID) + + dkgTimeoutSeconds := 20 + require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) + t.Log("waiting for initial set up to settle on all nodes") + + defer func() { + for _, inst := range instances { + // We want to ignore this error, at least until the stop command won't return an error + // when correctly running the stop command. + t.Logf("stopping instance %v\n", inst.addr) + err := inst.stopAll() + require.NoError(t, err) + t.Logf("stopped instance %v\n", inst.addr) + } + }() + + t.Log("waiting for initial setup to finish") + time.Sleep(5 * time.Second) + + // try to reload a beacon which is already loaded + err = instances[3].load(beaconID) + require.Error(t, err) + + // Stop beacon process... not the entire node + err = instances[3].stop(beaconID) + require.NoError(t, err) + + // check the node is still alive + testPing(t, instances[3].ctrlPort) + + t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") + time.Sleep(10 * time.Second) + + // reload a beacon + err = instances[3].load(beaconID) + require.NoError(t, err) + + // test beacon process status + testStatus(t, instances[3].ctrlPort, beaconID) + + time.Sleep(3 * time.Second) + + // test beacon process status + testStatus(t, instances[3].ctrlPort, beaconID) +} + +func TestDrandLoadNotPresentBeacon(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + n := 4 + instances := genAndLaunchDrandInstances(t, n) + + for i, inst := range instances { + if i == 0 { + inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) + } else { + inst.join(t, beaconID) + } + } + instances[0].executeDKG(t, beaconID) + + dkgTimeoutSeconds := 20 + + t.Log("waiting for initial set up to settle on all nodes") + err = instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds) + if err != nil { + t.Fatal(err) + } + + defer func() { + for _, inst := range instances { + _ = inst.stopAll() + } + }() + + t.Log("waiting for initial setup to finish") + time.Sleep(5 * time.Second) + + // Stop beacon process... not the entire node + err = instances[3].stop(beaconID) + require.NoError(t, err) + + t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") + time.Sleep(10 * time.Second) + + // reload a different beacon + err = instances[3].load("not-a-valid-beacon-name-here") + require.Error(t, err) + + // test original beacon process status and hope it's still off + testFailStatus(t, instances[3].ctrlPort, beaconID) +} + +func TestDrandStatus_WithoutDKG(t *testing.T) { + n := 4 + instances := genAndLaunchDrandInstances(t, n) + allAddresses := make([]string, 0, n) + for _, instance := range instances { + allAddresses = append(allAddresses, instance.addr) + } + + // check that each node can reach each other + for i, instance := range instances { + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + remote = append(remote, allAddresses...) + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + require.Contains(t, buff.String(), instance.addr+" -> OK") + } + } + // stop one and check that all nodes report this node down + toStop := 2 + insToStop := instances[toStop] + err := insToStop.stopAll() + require.NoError(t, err) + + for i, instance := range instances { + if i == toStop { + continue + } + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + remote = append(remote, allAddresses...) + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + if j != toStop { + require.Contains(t, buff.String(), instance.addr+" -> OK") + } else { + require.Contains(t, buff.String(), instance.addr+" -> X") + } + } + } +} + +func TestDrandStatus_WithDKG_NoAddress(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + n := 4 + instances := genAndLaunchDrandInstances(t, n) + + for i, inst := range instances { + if i == 0 { + inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) + } else { + inst.join(t, beaconID) + } + } + instances[0].executeDKG(t, beaconID) + + dkgTimeoutSeconds := 20 + require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) + t.Log("waiting for initial set up to settle on all nodes") + + // check that each node can reach each other + for i, instance := range instances { + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + require.Contains(t, buff.String(), instance.addr+" -> OK") + } + } + // stop one and check that all nodes report this node down + toStop := 2 + insToStop := instances[toStop] + err = insToStop.stopAll() + require.NoError(t, err) + + for i, instance := range instances { + if i == toStop { + continue + } + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + if j != toStop { + require.Contains(t, buff.String(), instance.addr+" -> OK") + } else { + require.Contains(t, buff.String(), instance.addr+" -> X") + } + } + } +} + +func TestDrandStatus_WithDKG_OneAddress(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + n := 4 + instances := genAndLaunchDrandInstances(t, n) + + for i, inst := range instances { + if i == 0 { + inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) + } else { + inst.join(t, beaconID) + } + } + instances[0].executeDKG(t, beaconID) + + dkgTimeoutSeconds := 20 + require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) + t.Log("waiting for initial set up to settle on all nodes") + + // check that each node can reach each other + for i, instance := range instances { + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + remote = append(remote, instances[i].addr) + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + require.Contains(t, buff.String(), instance.addr+" -> OK") + } + } + // stop one and check that all nodes report this node down + toStop := 2 + insToStop := instances[toStop] + err = insToStop.stopAll() + require.NoError(t, err) + + for i, instance := range instances { + if i == toStop { + continue + } + remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} + remote = append(remote, instances[i].addr) + var buff bytes.Buffer + + cli := CLI() + cli.Writer = &buff + + err := cli.Run(remote) + require.NoError(t, err) + for j, instance := range instances { + if i == j { + continue + } + if j != toStop { + require.Contains(t, buff.String(), instance.addr+" -> OK") + } else { + require.Contains(t, buff.String(), instance.addr+" -> X") + } + } + } +} + +func TestEmptyPortSelectionUsesDefaultDuringKeygen(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := t.TempDir() + app := CLI() + + // args are missing a port for the node address + args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} + // after being prompted for a port, the 'user' hits enter to select the default + app.Reader = strings.NewReader("\n") + + require.NoError(t, app.Run(args)) +} + +func TestValidPortSelectionSucceedsDuringKeygen(t *testing.T) { + beaconID := test.GetBeaconIDFromEnv() + + tmp := t.TempDir() + app := CLI() + + args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} + app.Reader = strings.NewReader("8080\n") + + require.NoError(t, app.Run(args)) +} + +type drandInstance struct { + path string + ctrlPort string + addr string + metrics string + certPath string + keyPath string + certsDir string +} + +func (d *drandInstance) stopAll() error { + return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort}) +} + +func (d *drandInstance) stop(beaconID string) error { + return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort, "--id", beaconID}) +} + +func (d *drandInstance) startInitialDKG( + t *testing.T, + l log.Logger, + instances []*drandInstance, + threshold, + //nolint:unparam // This is a parameter + periodSeconds int, + beaconID string, + sch *crypto.Scheme, +) { + t.Helper() + + addrs := make([]string, len(instances)) + for i, v := range instances { + addrs[i] = v.ctrlPort + } + + proposal, err := generateJoiningProposal(l, "default", addrs) + require.NoError(t, err) + + proposalPath := filepath.Join(t.TempDir(), "proposal.toml") + err = os.WriteFile(proposalPath, []byte(proposal), 0755) + require.NoError(t, err) + + dkgArgs := []string{ + "drand", + "dkg", + "propose", + "--proposal", proposalPath, + "--transition-time", fmt.Sprintf("%ds", 30*periodSeconds), + "--catchup-period", fmt.Sprintf("%ds", periodSeconds/2), + "--threshold", fmt.Sprintf("%d", threshold), + "--period", fmt.Sprintf("%ds", periodSeconds), + "--control", d.ctrlPort, + "--scheme", sch.Name, + "--id", beaconID, + } + + err = CLI().Run(dkgArgs) + require.NoError(t, err) +} + +func (d *drandInstance) executeDKG(t *testing.T, beaconID string) { + t.Helper() + dkgArgs := []string{ + "drand", + "dkg", + "execute", + "--control", d.ctrlPort, + "--id", beaconID, + } + + err := CLI().Run(dkgArgs) + require.NoError(t, err) +} + +func (d *drandInstance) awaitDKGComplete( + t *testing.T, + beaconID string, + //nolint:unparam // This is a parameter + epoch uint32, + timeoutSeconds int, +) error { + t.Helper() + dkgArgs := []string{ + "drand", + "dkg", + "status", + "--control", d.ctrlPort, + "--id", beaconID, + "--format", "csv", + } + + for i := 0; i < timeoutSeconds; i++ { + cli := CLI() + var buf bytes.Buffer + cli.Writer = &buf + + err := cli.Run(dkgArgs) + if err != nil { + return err + } + + statusOutput := buf.String() + expected := fmt.Sprintf("State:Complete,Epoch:%d,", epoch) + + if strings.Contains(statusOutput, expected) { + return nil + } + time.Sleep(1 * time.Second) + } + + return errors.New("DKG didn't complete within the timeout") +} + +func (d *drandInstance) load(beaconID string) error { + reloadArgs := []string{ + "drand", + "load", + "--control", d.ctrlPort, + "--id", beaconID, + } + + return CLI().Run(reloadArgs) +} + +func (d *drandInstance) run(t *testing.T, beaconID string) { + t.Helper() + + d.runWithStartArgs(t, beaconID, nil) +} + +func (d *drandInstance) runWithStartArgs(t *testing.T, beaconID string, startArgs []string) { + t.Helper() + + require.Equal(t, 0, len(startArgs)%2, "start args must be in pairs of option/value") + + baseArgs := []string{ + "drand", + "start", + "--verbose", + "--tls-cert", d.certPath, + "--tls-key", d.keyPath, + "--certs-dir", d.certsDir, + "--control", d.ctrlPort, + "--folder", d.path, + "--metrics", d.metrics, + "--private-listen", d.addr, + } + + baseArgs = append(baseArgs, startArgs...) + + go func() { + err := CLI().Run(baseArgs) + require.NoError(t, err) + }() + + // Prevent race condition in urfave/cli + time.Sleep(100 * time.Millisecond) + + // make sure we run each one sequentially + testStatus(t, d.ctrlPort, beaconID) +} + +func (d *drandInstance) join(t *testing.T, id string) { + t.Helper() + joinArgs := []string{ + "drand", + "dkg", + "join", + "--id", + id, + "--control", + d.ctrlPort, + } + + err := CLI().Run(joinArgs) + require.NoError(t, err) +} + +func genAndLaunchDrandInstances(t *testing.T, n int) []*drandInstance { + t.Helper() + + beaconID := test.GetBeaconIDFromEnv() + + ins := genDrandInstances(t, beaconID, n) + return launchDrandInstances(t, beaconID, ins) +} + +func genDrandInstances(t *testing.T, beaconID string, n int) []*drandInstance { + t.Helper() + + tmpPath := t.TempDir() + + certsDir := path.Join(tmpPath, "certs") + require.NoError(t, os.Mkdir(certsDir, 0o740)) + l := testlogger.New(t) + + ins := make([]*drandInstance, 0, n) + for i := 1; i <= n; i++ { + nodePath, err := os.MkdirTemp(tmpPath, "node") + require.NoError(t, err) + + certPath := path.Join(nodePath, "cert") + keyPath := path.Join(nodePath, "tls.key") + pubPath := path.Join(tmpPath, "pub.key") + + freePort := test.FreePort() + addr := "127.0.0.1:" + freePort + ctrlPort := test.FreePort() + metricsPort := test.FreePort() + + // generate key so it loads + // TODO let's remove this requirement - no need for longterm keys + priv, err := key.NewTLSKeyPair(addr, nil) + require.NoError(t, err) + require.NoError(t, key.Save(pubPath, priv.Public, false)) + config := core.NewConfig(l, core.WithConfigFolder(nodePath)) + fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) + err = fileStore.SaveKeyPair(priv) + require.NoError(t, err) + + h, _, err := gnet.SplitHostPort(addr) + require.NoError(t, err) + + err = httpscerts.Generate(certPath, keyPath, h) + require.NoError(t, err) + + // copy into one folder for giving a common CERT folder + _, err = exec.Command("cp", certPath, path.Join(certsDir, fmt.Sprintf("cert-%d", i))).Output() + require.NoError(t, err) + + ins = append(ins, &drandInstance{ + addr: addr, + ctrlPort: ctrlPort, + path: nodePath, + keyPath: keyPath, + metrics: metricsPort, + certPath: certPath, + certsDir: certsDir, + }) + } + + return ins +} + +func launchDrandInstances(t *testing.T, beaconID string, ins []*drandInstance) []*drandInstance { + t.Helper() + + for _, instance := range ins { + instance.run(t, beaconID) + } + return ins +} + +//nolint:funlen // This is a test +func TestMemDBBeaconReJoinsNetworkAfterLongStop(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + // How many rounds to generate while the node is stopped. + roundsWhileMissing := 50 + period := 1 + n := 4 + instances := genDrandInstances(t, beaconID, n) + memDBNodeID := len(instances) - 1 + + for i := 0; i < memDBNodeID; i++ { + inst := instances[i] + inst.run(t, beaconID) + } + + instances[memDBNodeID].runWithStartArgs(t, beaconID, []string{"--db", "memdb"}) + memDBNode := instances[memDBNodeID] + + for i, inst := range instances { + inst := inst + if i == 0 { + inst.startInitialDKG(t, l, instances, 3, period, beaconID, sch) + // Wait a bit after launching the leader to launch the other nodes too. + time.Sleep(500 * time.Millisecond) + } else { + inst.join(t, beaconID) + } + } + + instances[0].executeDKG(t, beaconID) + + t.Log("waiting for initial set up to settle on all nodes") + err = instances[0].awaitDKGComplete(t, beaconID, 1, 60) + require.NoError(t, err) + + defer func() { + for _, inst := range instances { + // We want to ignore this error, at least until the stop command won't return an error + // when correctly running the stop command. + t.Logf("stopping instance %v\n", inst.addr) + err := inst.stopAll() + require.NoError(t, err) + t.Logf("stopped instance %v\n", inst.addr) + } + }() + + memDBClient, err := net.NewControlClient(l, memDBNode.ctrlPort) + require.NoError(t, err) + + chainInfo, err := memDBClient.ChainInfo(beaconID) + require.NoError(t, err) + + // Wait until DKG finishes + secondsToGenesisTime := chainInfo.GenesisTime - time.Now().Unix() + t.Logf("waiting %ds until DKG finishes\n", secondsToGenesisTime) + time.Sleep(time.Duration(secondsToGenesisTime) * time.Second) + + // Wait for some rounds to be generated + t.Log("wait for some rounds to be generated") + time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) + + // Get the status before stopping the node + status, err := memDBClient.Status(beaconID) + require.NoError(t, err) + + require.False(t, status.ChainStore.IsEmpty) + require.NotZero(t, status.ChainStore.LastRound) + + lastRoundBeforeShutdown := status.ChainStore.LastRound + + // Stop beacon process... not the entire node + err = instances[memDBNodeID].stop(beaconID) + require.NoError(t, err) + + t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") + time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) + + // reload a beacon + err = instances[memDBNodeID].load(beaconID) + require.NoError(t, err) + + // Wait a bit to allow the node to startup and load correctly + time.Sleep(2 * time.Second) + + status, err = memDBClient.Status(beaconID) + require.NoError(t, err) + + require.False(t, status.ChainStore.IsEmpty) + require.NotZero(t, status.ChainStore.LastRound) + expectedRound := lastRoundBeforeShutdown + uint64(roundsWhileMissing) + t.Logf("comparing lastRound %d with lastRoundBeforeShutdown %d\n", status.ChainStore.LastRound, expectedRound) + require.GreaterOrEqual(t, status.ChainStore.LastRound, expectedRound) +} + +func TestDKGStatusDoesntBlowUp(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + l := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + beaconID := test.GetBeaconIDFromEnv() + + // start some nodes + n := 4 + instances := genAndLaunchDrandInstances(t, n) + + // execute a DKG + for i, inst := range instances { + if i == 0 { + inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) + } else { + inst.join(t, beaconID) + } + } + instances[0].executeDKG(t, beaconID) + + // wait for the DKG to finish + dkgTimeoutSeconds := 20 + require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) + t.Log("waiting for initial set up to settle on all nodes") + + // check the status command runs fine + err = CLI().Run([]string{"drand", "dkg", "status", "--control", instances[0].ctrlPort}) + require.NoError(t, err) +} diff --git a/internal/control.go b/internal/control.go new file mode 100644 index 0000000..0ab9c63 --- /dev/null +++ b/internal/control.go @@ -0,0 +1,535 @@ +package drand + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + "sync/atomic" + "time" + + "github.com/briandowns/spinner" + json "github.com/nikkolasg/hexjson" + "github.com/urfave/cli/v2" + + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/key" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/core" + "github.com/drand/drand/internal/core/migration" + "github.com/drand/drand/internal/net" + control "github.com/drand/drand/protobuf/drand" +) + +type beaconIDsStatuses struct { + Beacons map[string]*control.StatusResponse `json:"beacons"` +} + +func loadCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + beaconID := getBeaconID(c) + _, err = client.LoadBeacon(beaconID) + if err != nil { + return fmt.Errorf("could not reload the beacon process [%s]: %w", beaconID, err) + } + + fmt.Fprintf(c.App.Writer, "Beacon process [%s] was loaded on drand.\n", beaconID) + return nil +} + +func remoteStatusCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + ips := c.Args().Slice() + isTLS := !c.IsSet(insecureFlag.Name) + beaconID := getBeaconID(c) + + addresses := make([]*control.Address, len(ips)) + for i := 0; i < len(ips); i++ { + addresses[i] = &control.Address{ + Address: ips[i], + Tls: isTLS, + } + } + + resp, err := client.RemoteStatus(c.Context, addresses, beaconID) + if err != nil { + return err + } + // set default value for all keys so json outputs something for all keys + defaultMap := make(map[string]*control.StatusResponse) + switch { + case len(addresses) > 0: + for _, addr := range addresses { + if resp, ok := resp[addr.GetAddress()]; !ok { + defaultMap[addr.GetAddress()] = nil + } else { + defaultMap[addr.GetAddress()] = resp + } + } + default: + defaultMap = resp + } + + if c.IsSet(jsonFlag.Name) { + str, err := json.Marshal(defaultMap) + if err != nil { + return fmt.Errorf("cannot marshal the response ... %w", err) + } + fmt.Fprintf(c.App.Writer, "%s \n", string(str)) + } else { + for addr, resp := range defaultMap { + fmt.Fprintf(c.App.Writer, "Status of beacon %s on node %s\n", beaconID, addr) + if resp == nil { + fmt.Fprintf(c.App.Writer, "\t- NO STATUS; can't connect\n") + } else { + fmt.Fprintf(c.App.Writer, "%s\n", core.StatusResponseToString(resp)) + } + } + } + return nil +} + +func pingpongCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + if err := client.Ping(); err != nil { + return fmt.Errorf("drand: can't ping the daemon ... %w", err) + } + fmt.Fprintf(c.App.Writer, "drand daemon is alive on port %s\n", controlPort(c)) + return nil +} + +func remotePingToNode(l log.Logger, addr string, tls bool) error { + peer := net.CreatePeer(addr, tls) + client := net.NewGrpcClient(l) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, err := client.Home(ctx, peer, &control.HomeRequest{}) + if err != nil { + return err + } + + return nil +} + +//nolint:gocyclo +func statusCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + listIds := c.IsSet(listIdsFlag.Name) + allIds := c.IsSet(allBeaconsFlag.Name) + beaconID := c.IsSet(beaconIDFlag.Name) + + if beaconID && (allIds || listIds) { + return fmt.Errorf("drand: can't use --%s with --%s or --%s flags at the same time", + beaconIDFlag.Name, allBeaconsFlag.Name, listIdsFlag.Name) + } + + beaconIDsList := &control.ListBeaconIDsResponse{} + if allIds || listIds { + beaconIDsList, err = client.ListBeaconIDs() + if err != nil { + return fmt.Errorf("drand: can't get the list of running beacon ids on the daemon ... %w", err) + } + } else { + beaconIDsList.Ids = append(beaconIDsList.Ids, getBeaconID(c)) + } + + if listIds { + if c.IsSet(jsonFlag.Name) { + str, err := json.Marshal(beaconIDsList) + if err != nil { + return fmt.Errorf("cannot marshal the response ... %w", err) + } + fmt.Fprintf(c.App.Writer, "%s \n", string(str)) + return nil + } + + fmt.Fprintf(c.App.Writer, "running beacon ids on the node: [%s]\n", strings.Join(beaconIDsList.Ids, ", ")) + return nil + } + + statuses := beaconIDsStatuses{Beacons: make(map[string]*control.StatusResponse)} + for _, id := range beaconIDsList.Ids { + resp, err := client.Status(id) + if err != nil { + return fmt.Errorf("drand: can't get the status of the network with id [%s]... %w", id, err) + } + + if c.IsSet(jsonFlag.Name) { + statuses.Beacons[id] = resp + continue + } + + fmt.Fprintf(c.App.Writer, "the status of network with id [%s] is: \n", id) + fmt.Fprintf(c.App.Writer, "%s \n", core.StatusResponseToString(resp)) + } + + if c.IsSet(jsonFlag.Name) { + str, err := json.Marshal(statuses) + if err != nil { + return fmt.Errorf("cannot marshal the response ... %w", err) + } + fmt.Fprintf(c.App.Writer, "%s \n", string(str)) + } + + return nil +} + +func migrateCmd(c *cli.Context, l log.Logger) error { + conf := contextToConfig(c, l) + + if err := migration.MigrateSBFolderStructure(conf.ConfigFolder()); err != nil { + return fmt.Errorf("cannot migrate folder structure, please try again. err: %w", err) + } + + fmt.Fprintf(c.App.Writer, "folder structure is now ready to support multi-beacon drand\n") + return nil +} + +func schemesCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + resp, err := client.ListSchemes() + if err != nil { + return fmt.Errorf("drand: can't get the list of scheme ids availables ... %w", err) + } + + fmt.Fprintf(c.App.Writer, "Drand supports the following list of schemes: \n") + + for i, id := range resp.Ids { + fmt.Fprintf(c.App.Writer, "%d) %s \n", i, id) + } + + fmt.Fprintf(c.App.Writer, "\nChoose one of them and set it on --%s flag \n", schemeFlag.Name) + return nil +} + +func showGroupCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + beaconID := getBeaconID(c) + r, err := client.GroupFile(beaconID) + if err != nil { + return fmt.Errorf("fetching group file error: %w", err) + } + + group, err := key.GroupFromProto(r, nil) + if err != nil { + return err + } + + return groupOut(c, group) +} + +func showChainInfo(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + beaconID := getBeaconID(c) + resp, err := client.ChainInfo(beaconID) + if err != nil { + return fmt.Errorf("could not request chain info: %w", err) + } + + ci, err := chain.InfoFromProto(resp) + if err != nil { + return fmt.Errorf("could not get correct chain info: %w", err) + } + + return printChainInfo(c, ci) +} + +func showPublicCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + beaconID := getBeaconID(c) + resp, err := client.PublicKey(beaconID) + if err != nil { + return fmt.Errorf("drand: could not request drand.public: %w", err) + } + + return printJSON(c.App.Writer, resp) +} + +func backupDBCmd(c *cli.Context, l log.Logger) error { + client, err := controlClient(c, l) + if err != nil { + return err + } + + outDir := c.String(backupOutFlag.Name) + beaconID := getBeaconID(c) + err = client.BackupDB(outDir, beaconID) + if err != nil { + return fmt.Errorf("could not back up: %w", err) + } + + return nil +} + +func controlPort(c *cli.Context) string { + port := c.String(controlFlag.Name) + if port == "" { + port = core.DefaultControlPort + } + return port +} + +func controlClient(c *cli.Context, l log.Logger) (*net.ControlClient, error) { + port := controlPort(c) + client, err := net.NewControlClient(l, port) + if err != nil { + return nil, fmt.Errorf("can't instantiate control client: %w", err) + } + return client, nil +} + +func printJSON(w io.Writer, j interface{}) error { + buff, err := json.MarshalIndent(j, "", " ") + if err != nil { + return fmt.Errorf("could not JSON marshal: %w", err) + } + fmt.Fprintln(w, string(buff)) + return nil +} + +func selfSign(c *cli.Context, l log.Logger) error { + conf := contextToConfig(c, l) + + beaconID := getBeaconID(c) + + fs := key.NewFileStore(conf.ConfigFolderMB(), beaconID) + pair, err := fs.LoadKeyPair(nil) + + if err != nil { + return fmt.Errorf("beacon id [%s] - loading private/public: %w", beaconID, err) + } + if pair.Public.ValidSignature() == nil { + fmt.Fprintf(c.App.Writer, "beacon id [%s] - public identity already self signed.\n", beaconID) + return nil + } + + if err := pair.SelfSign(); err != nil { + return fmt.Errorf("failed to self-sign keypair for beacon id [%s]: %w", beaconID, err) + } + if err := fs.SaveKeyPair(pair); err != nil { + return fmt.Errorf("beacon id [%s] - saving identity: %w", beaconID, err) + } + + fmt.Fprintf(c.App.Writer, "beacon id [%s] - Public identity self signed for scheme %s", beaconID, pair.Scheme().Name) + fmt.Fprintln(c.App.Writer, printJSON(c.App.Writer, pair.Public.TOML())) + return nil +} + +const refreshRate = 500 * time.Millisecond + +//nolint:funlen +func checkCmd(c *cli.Context, l log.Logger) error { + defer l.Infow("Finished sync") + + ctrlClient, err := controlClient(c, l) + if err != nil { + return fmt.Errorf("unable to create control client: %w", err) + } + + addrs := strings.Split(c.String(syncNodeFlag.Name), ",") + + channel, errCh, err := ctrlClient.StartCheckChain( + c.Context, + c.String(hashInfoReq.Name), + addrs, + !c.Bool(insecureFlag.Name), + uint64(c.Int(upToFlag.Name)), + c.String(beaconIDFlag.Name)) + + if err != nil { + l.Errorw("Error checking chain", "err", err) + return fmt.Errorf("error asking to check chain up to %d: %w", c.Int(upToFlag.Name), err) + } + + var current uint64 + target := uint64(c.Int(upToFlag.Name)) + s := spinner.New(spinner.CharSets[9], refreshRate) + s.PreUpdate = func(spin *spinner.Spinner) { + curr := atomic.LoadUint64(¤t) + spin.Suffix = fmt.Sprintf(" synced round up to %d "+ + "\t- current target %d"+ + "\t--> %.3f %% - "+ + "Waiting on new rounds...", curr, target, 100*float64(curr)/float64(target)) + } + s.Start() + defer s.Stop() + + // The following could be much simpler if we don't want to be nice on the user and display comprehensive logs + // on the client side. + isCorrecting, success := false, false + for { + select { + case progress, ok := <-channel: + if !ok { + // let the spinner time to refresh + time.Sleep(refreshRate) + if success { + // we need an empty line to not clash with the spinner + fmt.Println() + l.Infow("Finished correcting faulty beacons, " + + "we recommend running the same command a second time to confirm all beacons are now valid") + } + return nil + } + // if we received at least one progress update after switching to correcting + success = isCorrecting + if progress.Current == 0 { + // let the spinner time to refresh + time.Sleep(refreshRate) + // we need an empty line to not clash with the spinner + fmt.Println() + l.Infow("Finished checking chain validity") + if progress.Target > 0 { + l.Warnw("Faulty beacon found!", "amount", progress.Target) + isCorrecting = true + } else { + l.Warnw("No faulty beacon found!") + } + } + atomic.StoreUint64(¤t, progress.Current) + atomic.StoreUint64(&target, progress.Target) + case err, ok := <-errCh: + if !ok { + l.Infow("Error channel was closed") + return nil + } + // note that grpc's "error reading from server: EOF" won't trigger this so we really only catch the case + // where the server gracefully closed the connection. + if errors.Is(err, io.EOF) { + // let the spinner time to refresh + time.Sleep(refreshRate) + // make sure to exhaust our progress channel + progress, ok := <-channel + if ok { + if atomic.LoadUint64(&target) > progress.Target { + // we need an empty line to not clash with the spinner + fmt.Println() + l.Infow("Finished checking chain validity") + l.Warnw("Faulty beacon found!", "amount", progress.Target) + } else { + atomic.StoreUint64(¤t, progress.Current) + // let the spinner time to refresh again + time.Sleep(refreshRate) + // we need an empty line to not clash with the spinner + fmt.Println() + } + } + + if success { + // we need an empty line to not clash with the spinner + fmt.Println() + l.Infow("Finished correcting faulty beacons, " + + "we recommend running the same command a second time to confirm all beacons are now valid") + } + + return nil + } + + l.Errorw("received an error", "err", err) + return fmt.Errorf("errror when checking the chain: %w", err) + } + } +} + +func syncCmd(c *cli.Context, l log.Logger) error { + if c.Bool(followFlag.Name) { + return followSync(c, l) + } + + return checkCmd(c, l) +} + +func followSync(c *cli.Context, l log.Logger) error { + ctrlClient, err := controlClient(c, l) + if err != nil { + return fmt.Errorf("unable to create control client: %w", err) + } + defer ctrlClient.Close() + + addrs := strings.Split(c.String(syncNodeFlag.Name), ",") + channel, errCh, err := ctrlClient.StartFollowChain( + c.Context, + c.String(hashInfoReq.Name), + addrs, + !c.Bool(insecureFlag.Name), + uint64(c.Int(upToFlag.Name)), + getBeaconID(c)) + + if err != nil { + return fmt.Errorf("error asking to follow chain: %w", err) + } + + var current uint64 + var target uint64 + + last := time.Now().Unix() + + s := spinner.New(spinner.CharSets[9], refreshRate) + s.PreUpdate = func(spin *spinner.Spinner) { + curr := atomic.LoadUint64(¤t) + tar := atomic.LoadUint64(&target) + dur := time.Now().Unix() - atomic.LoadInt64(&last) + + spin.Suffix = fmt.Sprintf(" synced round up to %d "+ + "- current target %d"+ + "\t--> %.3f %% - "+ + "Last update received %3ds ago. Waiting on new rounds...", curr, tar, 100*float64(curr)/float64(tar), dur) + } + + s.FinalMSG = "\nSync stopped\n" + + s.Start() + defer s.Stop() + for { + select { + case progress := <-channel: + atomic.StoreUint64(¤t, progress.Current) + atomic.StoreUint64(&target, progress.Target) + atomic.StoreInt64(&last, time.Now().Unix()) + case err := <-errCh: + if errors.Is(err, io.EOF) { + // we need a new line because of the spinner + fmt.Println() + l.Infow("Finished following beacon chain", "reached", current, + "server closed stream with", err) + return nil + } + return fmt.Errorf("errror on following the chain: %w", err) + } + } +} diff --git a/internal/daemon.go b/internal/daemon.go new file mode 100644 index 0000000..de43651 --- /dev/null +++ b/internal/daemon.go @@ -0,0 +1,80 @@ +package drand + +import ( + "fmt" + + "github.com/urfave/cli/v2" + "go.opentelemetry.io/otel/attribute" + + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/core" + "github.com/drand/drand/internal/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(ctx, conf) + if err != nil { + 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(ctx, c.String(metricsFlag.Name), singleBeacon, c.String(beaconIDFlag.Name)) + if err != nil { + err = fmt.Errorf("couldn't load existing beacons: %w", err) + span.RecordError(err) + span.End() + return err + } + + span.End() + <-drandDaemon.WaitExit() + return nil +} + +func stopDaemon(c *cli.Context, lg log.Logger) error { + ctrlClient, err := controlClient(c, lg) + if err != nil { + return err + } + defer ctrlClient.Close() + + isBeaconIDSet := c.IsSet(beaconIDFlag.Name) + if isBeaconIDSet { + beaconID := getBeaconID(c) + _, err = ctrlClient.Shutdown(beaconID) + + if err != nil { + return fmt.Errorf("error stopping beacon process [%s]: %w", beaconID, err) + } + fmt.Fprintf(c.App.Writer, "beacon process [%s] stopped correctly. Bye.\n", beaconID) + } else { + _, err = ctrlClient.Shutdown("") + + if err != nil { + return fmt.Errorf("error stopping drand daemon: %w", err) + } + fmt.Fprintf(c.App.Writer, "drand daemon stopped correctly. Bye.\n") + } + + return nil +} diff --git a/internal/dkg_cli.go b/internal/dkg_cli.go new file mode 100644 index 0000000..c2d8ec3 --- /dev/null +++ b/internal/dkg_cli.go @@ -0,0 +1,789 @@ +package drand + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + "os" + "strconv" + "strings" + "time" + + "github.com/BurntSushi/toml" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/urfave/cli/v2" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/drand/drand/common" + "github.com/drand/drand/common/key" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/chain" + "github.com/drand/drand/internal/core" + "github.com/drand/drand/internal/dkg" + "github.com/drand/drand/internal/net" + "github.com/drand/drand/internal/util" + common2 "github.com/drand/drand/protobuf/common" + "github.com/drand/drand/protobuf/drand" +) + +var dkgCommand = &cli.Command{ + Name: "dkg", + Usage: "Commands for interacting with the DKG", + Subcommands: []*cli.Command{ + { + Name: "propose", + Flags: toArray( + beaconIDFlag, + controlFlag, + schemeFlag, + periodFlag, + thresholdFlag, + catchupPeriodFlag, + proposalFlag, + secretFlag, + dkgTimeoutFlag, + transitionTimeFlag, + ), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("dkgPropose") + return makeProposal(c, l) + }, + }, + { + Name: "join", + Flags: toArray( + beaconIDFlag, + controlFlag, + secretFlag, + groupFlag, + ), + Action: joinNetwork, + }, + { + Name: "execute", + Flags: toArray( + beaconIDFlag, + controlFlag, + ), + Action: executeDKG, + }, + { + Name: "accept", + Flags: toArray( + beaconIDFlag, + controlFlag, + ), + Action: acceptDKG, + }, + { + Name: "reject", + Flags: toArray( + beaconIDFlag, + controlFlag, + ), + Action: rejectDKG, + }, + { + Name: "abort", + Flags: toArray( + beaconIDFlag, + controlFlag, + ), + Action: abortDKG, + }, + { + Name: "status", + Flags: toArray( + beaconIDFlag, + controlFlag, + formatFlag, + ), + Action: viewStatus, + }, + { + Name: "generate-proposal", + Flags: toArray( + joinerFlag, + remainerFlag, + proposalOutputFlag, + beaconIDFlag, + controlFlag, + leaverFlag, + ), + Action: func(c *cli.Context) error { + l := log.New(nil, logLevel(c), logJSON(c)). + Named("dkgGenerateProposal") + return generateProposalCmd(c, l) + }, + }, + }, +} + +var joinerFlag = &cli.StringSliceFlag{ + Name: "joiner", + Usage: "the address of a joiner you wish to add to a DKG proposal. You can pass it multiple times. " + + "To use TLS, prefix their address with 'https://'", +} + +var remainerFlag = &cli.StringSliceFlag{ + Name: "remainer", + Usage: "the address of a remainer you wish to add to a DKG proposal. You can pass it multiple times. " + + "To use TLS, prefix their address with 'https://'", +} + +var leaverFlag = &cli.StringSliceFlag{ + Name: "leaver", + Usage: "the address of a leaver you wish to add to the DKG proposal. You can pass it multiple times. " + + "To use TLS, prefix their address with 'https://'", +} + +var proposalOutputFlag = &cli.StringFlag{ + Name: "out", + Usage: "the location you wish to save the proposal file to", +} + +var formatFlag = &cli.StringFlag{ + Name: "format", + Usage: "Set the format of the status output. Valid options are: pretty, csv", + Value: "pretty", + EnvVars: []string{"DRAND_STATUS_FORMAT"}, +} + +var transitionTimeFlag = &cli.StringFlag{ + Name: "transition-time", + Usage: "The duration from now until which keys generated during the next DKG should be used. It will be modified to the nearest round.", +} + +var dkgTimeoutFlag = &cli.StringFlag{ + Name: "timeout", + Usage: "The duration from now in which DKG participants should abort the DKG if it has not completed.", + Value: "24h", +} + +func makeProposal(c *cli.Context, l log.Logger) error { + controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) + client, err := net.NewDKGControlClient(l, controlPort) + if err != nil { + return err + } + + beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) + + if isInitialProposal(c) { + proposal, err := parseInitialProposal(c) + if err != nil { + return err + } + + _, err = client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Initial{Initial: proposal}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + if err != nil { + return err + } + } else { + proposal, err := parseProposal(c, l) + if err != nil { + return err + } + + _, err = client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Resharing{Resharing: proposal}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + if err != nil { + return fmt.Errorf("proposal was unsuccessful - you may need to issue an abort command. Error: %w", err) + } + } + + fmt.Println("Proposal made successfully!") + return nil +} + +func isInitialProposal(c *cli.Context) bool { + return c.IsSet(schemeFlag.Name) +} + +func withDefault(first, second string) string { + if first == "" { + return second + } + + return first +} + +func parseInitialProposal(c *cli.Context) (*drand.FirstProposalOptions, error) { + requiredFlags := []*cli.StringFlag{proposalFlag, periodFlag, schemeFlag, catchupPeriodFlag, transitionTimeFlag} + + for _, flag := range requiredFlags { + if !c.IsSet(flag.Name) { + return nil, fmt.Errorf("%s flag is required for initial proposals", flag.Name) + } + } + + // this is IntFlag and not StringFlag so must be checked separately + if !c.IsSet(thresholdFlag.Name) { + return nil, fmt.Errorf("%s flag is required for initial proposals", thresholdFlag.Name) + } + + proposalFile, err := ParseProposalFile(c.String(proposalFlag.Name)) + if err != nil { + return nil, err + } + + err = validateInitialProposal(proposalFile) + if err != nil { + return nil, err + } + + period := c.Duration(periodFlag.Name) + timeout := time.Now().Add(c.Duration(dkgTimeoutFlag.Name)) + + genesisTime := time.Now().Add(c.Duration(transitionTimeFlag.Name)) + + return &drand.FirstProposalOptions{ + Timeout: timestamppb.New(timeout), + Threshold: uint32(c.Int(thresholdFlag.Name)), + PeriodSeconds: uint32(period.Seconds()), + Scheme: c.String(schemeFlag.Name), + CatchupPeriodSeconds: uint32(c.Duration(catchupPeriodFlag.Name).Seconds()), + GenesisTime: timestamppb.New(genesisTime), + Joining: proposalFile.Joining, + }, nil +} + +func validateInitialProposal(proposalFile *ProposalFile) error { + if len(proposalFile.Leaving) != 0 || len(proposalFile.Remaining) != 0 { + return fmt.Errorf("your proposal file must not have `Leaving` or `Remaining` for an initial DKG proposal") + } + + if len(proposalFile.Joining) == 0 { + return fmt.Errorf("your proposal file must have `Joining`") + } + + return nil +} + +func parseProposal(c *cli.Context, l log.Logger) (*drand.ProposalOptions, error) { + beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) + bannedFlags := []*cli.StringFlag{periodFlag, schemeFlag} + for _, flag := range bannedFlags { + if c.IsSet(flag.Name) { + return nil, fmt.Errorf("%s flag can only be set for initial proposals", flag.Name) + } + } + + if !c.IsSet(proposalFlag.Name) { + return nil, fmt.Errorf("%s flag is required ", proposalFlag.Name) + } + + if !c.IsSet(thresholdFlag.Name) { + return nil, fmt.Errorf("%s flag is required", thresholdFlag.Name) + } + + // parse a proposal file from the path specified + proposalFilePath := c.String(proposalFlag.Name) + proposalFile, err := ParseProposalFile(proposalFilePath) + if err != nil { + return nil, err + } + + if len(proposalFile.Remaining) == 0 { + return nil, fmt.Errorf("you must provider remainers for a proposal") + } + + var timeout time.Time + if c.IsSet(dkgTimeoutFlag.Name) { + timeout = time.Now().Add(c.Duration(dkgTimeoutFlag.Name)) + } else { + timeout = time.Now().Add(core.DefaultDKGTimeout) + } + + // figure out the round closest to the transition duration provided + var transitionTime time.Time + if c.IsSet(transitionTimeFlag.Name) { + transitionTime = time.Now().Add(c.Duration(transitionTimeFlag.Name)) + } else { + transitionTime = time.Now().Add(1 * time.Minute) + } + + // first we get the chainInfo for the beacon + var ctrlPort string + if c.IsSet(controlFlag.Name) { + ctrlPort = c.String(controlFlag.Name) + } else { + ctrlPort = core.DefaultControlPort + } + + ctrlClient, err := net.NewControlClient(l, ctrlPort) + if err != nil { + return nil, err + } + info, err := ctrlClient.ChainInfo(beaconID) + if err != nil { + return nil, err + } + + // then we use it to work out the real transition time + transitionRound := chain.CurrentRound(transitionTime.Unix(), time.Duration(info.Period)*time.Second, info.GenesisTime) + actualTransitionTime := chain.TimeOfRound(time.Duration(info.Period)*time.Second, info.GenesisTime, transitionRound) + + return &drand.ProposalOptions{ + Timeout: timestamppb.New(timeout), + TransitionTime: timestamppb.New(time.Unix(actualTransitionTime, 0)), + Threshold: uint32(c.Int(thresholdFlag.Name)), + CatchupPeriodSeconds: uint32(c.Duration(catchupPeriodFlag.Name).Seconds()), + Joining: proposalFile.Joining, + Leaving: proposalFile.Leaving, + Remaining: proposalFile.Remaining, + }, nil +} + +func joinNetwork(c *cli.Context) error { + l := log.FromContextOrDefault(c.Context) + beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) + controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) + + var groupFile []byte + if c.IsSet(groupFlag.Name) { + fileContents, err := os.ReadFile(c.String(groupFlag.Name)) + if err != nil { + return err + } + groupFile = fileContents + } + + client, err := net.NewDKGControlClient(l, controlPort) + if err != nil { + return err + } + _, err = client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Join{Join: &drand.JoinOptions{ + GroupFile: groupFile, + }}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + + if err == nil { + fmt.Println("Joined the DKG successfully!") + } + return err +} + +func executeDKG(c *cli.Context) error { + err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { + _, err := client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Execute{Execute: &drand.ExecutionOptions{}}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + return err + }) + + if err == nil { + fmt.Println("DKG execution started successfully!") + } + return err +} + +func acceptDKG(c *cli.Context) error { + err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { + _, err := client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Accept{Accept: &drand.AcceptOptions{}}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + return err + }) + + if err == nil { + fmt.Println("DKG accepted successfully!") + } + return err +} + +func rejectDKG(c *cli.Context) error { + err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { + _, err := client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Reject{Reject: &drand.RejectOptions{}}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + return err + }) + + if err == nil { + fmt.Println("DKG rejected successfully!") + } + + return err +} + +func abortDKG(c *cli.Context) error { + err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { + _, err := client.Command(c.Context, &drand.DKGCommand{ + Command: &drand.DKGCommand_Abort{Abort: &drand.AbortOptions{}}, + Metadata: &drand.CommandMetadata{ + BeaconID: beaconID, + }, + }) + return err + }) + if err == nil { + fmt.Println("DKG aborted successfully!") + } + return err +} + +func runSimpleAction(c *cli.Context, action func(beaconID string, client drand.DKGControlClient) error) error { + l := log.FromContextOrDefault(c.Context) + beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) + controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) + + client, err := net.NewDKGControlClient(l, controlPort) + if err != nil { + return err + } + return action(beaconID, client) +} + +func viewStatus(c *cli.Context) error { + l := log.FromContextOrDefault(c.Context) + var beaconID string + if c.IsSet(beaconIDFlag.Name) { + beaconID = c.String(beaconIDFlag.Name) + } else { + beaconID = common.DefaultBeaconID + } + + var controlPort string + if c.IsSet(controlFlag.Name) { + controlPort = c.String(controlFlag.Name) + } else { + controlPort = core.DefaultControlPort + } + + client, err := net.NewDKGControlClient(l, controlPort) + if err != nil { + return err + } + + status, err := client.DKGStatus(context.Background(), &drand.DKGStatusRequest{BeaconID: beaconID}) + if err != nil { + return err + } + + if !c.IsSet(formatFlag.Name) || c.String(formatFlag.Name) == "pretty" { + prettyPrint(status) + } else if c.String(formatFlag.Name) == "csv" { + csvPrint(c, "<>", status.Current) + csvPrint(c, "<>", status.Complete) + } else { + return errors.New("invalid format flag") + } + return nil +} + +func csvPrint(c *cli.Context, tag string, entry *drand.DKGEntry) { + out := c.App.Writer + _, _ = fmt.Fprintf(out, "%s", tag) + if entry == nil { + _, _ = fmt.Fprintln(out, "nil") + return + } + + _, err := fmt.Fprintf( + c.App.Writer, + "BeaconID:%s,State:%s,Epoch:%d,Threshold:%d,Timeout:%s,GenesisTime:%s,TransitionTime:%s,GenesisSeed:%s,Leader:%s", + entry.BeaconID, + dkg.Status(entry.State).String(), + entry.Epoch, + entry.Threshold, + entry.Timeout.AsTime().String(), + entry.GenesisTime.AsTime().String(), + entry.TransitionTime.AsTime().String(), + hex.EncodeToString(entry.GenesisSeed), + entry.Leader.Address, + ) + if err != nil { + _, _ = fmt.Fprintln(out, "error") + } +} + +type printModel struct { + Status string + BeaconID string + Epoch string + Threshold string + Timeout string + GenesisTime string + TransitionTime string + GenesisSeed string + Leader string + Joining string + Remaining string + Leaving string + Accepted string + Rejected string + FinalGroup string +} + +func convert(entry *drand.DKGEntry) printModel { + formatAddresses := func(arr []*drand.Participant) string { + if len(arr) == 0 { + return "[]" + } + if len(arr) == 1 { + return fmt.Sprintf("[%s]", arr[0].Address) + } + + b := strings.Builder{} + b.WriteString("[") + for _, a := range arr { + b.WriteString(fmt.Sprintf("\n\t%s,", a.Address)) + } + b.WriteString("\n]") + + return b.String() + } + + formatFinalGroup := func(group []string) string { + if group == nil { + return "" + } + b := strings.Builder{} + b.WriteString("[") + for _, a := range group { + b.WriteString(fmt.Sprintf("\n\t%s,", a)) + } + b.WriteString("\n]") + return b.String() + } + + return printModel{ + Status: dkg.Status(entry.State).String(), + BeaconID: entry.BeaconID, + Epoch: strconv.Itoa(int(entry.Epoch)), + Threshold: strconv.Itoa(int(entry.Threshold)), + Timeout: entry.Timeout.AsTime().Format(time.RFC3339), + GenesisTime: entry.GenesisTime.AsTime().Format(time.RFC3339), + TransitionTime: entry.TransitionTime.AsTime().Format(time.RFC3339), + GenesisSeed: hex.EncodeToString(entry.GenesisSeed), + Leader: entry.Leader.Address, + Joining: formatAddresses(entry.Joining), + Remaining: formatAddresses(entry.Remaining), + Leaving: formatAddresses(entry.Leaving), + Accepted: formatAddresses(entry.Acceptors), + Rejected: formatAddresses(entry.Rejectors), + FinalGroup: formatFinalGroup(entry.FinalGroup), + } +} + +func prettyPrint(status *drand.DKGStatusResponse) { + tw := table.NewWriter() + tw.AppendHeader(table.Row{"Field", "Current", "Finished"}) + + if dkg.Status(status.Current.State) == dkg.Fresh { + tw.AppendRow(table.Row{"State", "Fresh", "Fresh"}) + fmt.Println(tw.Render()) + return + } + + currentModel := convert(status.Current) + finishedModel := convert(status.Complete) + + tw.AppendRow(table.Row{"Status", currentModel.Status, finishedModel.Status}) + tw.AppendRow(table.Row{"Epoch", currentModel.Epoch, finishedModel.Epoch}) + tw.AppendRow(table.Row{"BeaconID", currentModel.BeaconID, finishedModel.BeaconID}) + tw.AppendRow(table.Row{"Threshold", currentModel.Threshold, finishedModel.Threshold}) + tw.AppendRow(table.Row{"Timeout", currentModel.Timeout, finishedModel.Timeout}) + tw.AppendRow(table.Row{"GenesisTime", currentModel.GenesisTime, finishedModel.GenesisTime}) + tw.AppendRow(table.Row{"TransitionTime", currentModel.TransitionTime, finishedModel.TransitionTime}) + tw.AppendRow(table.Row{"GenesisSeed", currentModel.GenesisSeed, finishedModel.GenesisSeed}) + tw.AppendRow(table.Row{"Leader", currentModel.Leader, finishedModel.Leader}) + tw.AppendRow(table.Row{"Joining", currentModel.Joining, finishedModel.Joining}) + tw.AppendRow(table.Row{"Remaining", currentModel.Remaining, finishedModel.Remaining}) + tw.AppendRow(table.Row{"Leaving", currentModel.Leaving, finishedModel.Leaving}) + tw.AppendRow(table.Row{"Accepted", currentModel.Accepted, finishedModel.Accepted}) + tw.AppendRow(table.Row{"Rejected", currentModel.Rejected, finishedModel.Rejected}) + tw.AppendRow(table.Row{"FinalGroup", currentModel.FinalGroup, finishedModel.FinalGroup}) + + fmt.Println(tw.Render()) +} + +func generateProposalCmd(c *cli.Context, l log.Logger) error { + // first we validate the flags + if !c.IsSet(joinerFlag.Name) && !c.IsSet(remainerFlag.Name) { + return errors.New("you must add joiners and/or remainers to the proposal") + } + + if !c.IsSet(proposalOutputFlag.Name) { + return errors.New("you must pass an output filepath for the proposal") + } + + var beaconID string + if c.IsSet(beaconIDFlag.Name) { + beaconID = c.String(beaconIDFlag.Name) + } else { + beaconID = common.DefaultBeaconID + } + + // then we fetch the current group file + proposalFile := ProposalFile{} + client, err := controlClient(c, l) + if err != nil { + return err + } + + freshStart := false + r, err := client.GroupFile(beaconID) + + if err != nil { + // if it's a fresh start, we'll take a different path + if errors.Is(err, core.ErrNoGroupSetup) { + freshStart = true + } else { + return err + } + } + + joiners := c.StringSlice(joinerFlag.Name) + remainers := c.StringSlice(remainerFlag.Name) + leavers := c.StringSlice(leaverFlag.Name) + + if freshStart { + if len(remainers) > 0 { + return errors.New("the network isn't running yet - cannot have remainers") + } + if len(leavers) > 0 { + return errors.New("the network isn't running yet - cannot have leavers") + } + } else { + current := make([]*drand.Participant, len(r.Nodes)) + for i, node := range r.Nodes { + address := node.Public.Address + if !util.Cont(util.Concat(remainers, leavers), address) { + return fmt.Errorf("%s is missing in the attempted proposal but exists in the current network. It should be leaving or remaining", address) + } + current[i] = util.ToParticipant(node) + } + + for _, remainer := range remainers { + matching, err := util.First(current, func(participant *drand.Participant) bool { + return participant.Address == remainer + }) + if err != nil { + return fmt.Errorf("remainer %s is missing in the current network", remainer) + } + proposalFile.Remaining = append(proposalFile.Remaining, *matching) + } + + for _, leaver := range leavers { + matching, err := util.First(current, func(participant *drand.Participant) bool { + return participant.Address == leaver + }) + if err != nil { + return fmt.Errorf("leaver %s is missing in the current network", leaver) + } + proposalFile.Leaving = append(proposalFile.Leaving, *matching) + } + } + + identityResp, err := client.PublicKey(beaconID) + if err != nil { + return err + } + sch, err := crypto.SchemeFromName(identityResp.GetSchemeName()) + if err != nil { + return key.ErrInvalidKeyScheme + } + + id, err := key.IdentityFromProto(&drand.Identity{ + Signature: identityResp.Signature, + Tls: identityResp.Tls, + Address: identityResp.Addr, + Key: identityResp.PubKey, + }, sch) + if err != nil { + return key.ErrInvalidKeyScheme + } + + if err = id.ValidSignature(); err != nil { + return key.ErrInvalidKeyScheme + } + + // we fetch the keys for all the new joiners by calling their node's API + for _, joiner := range joiners { + p, err := fetchPublicKey(beaconID, l, joiner, sch) + if err != nil { + return err + } + proposalFile.Joining = append(proposalFile.Joining, p) + } + + // finally we write the proposal toml file to the output location + filepath := c.String(proposalOutputFlag.Name) + file, err := os.Create(filepath) + if err != nil { + return err + } + + err = toml.NewEncoder(file).Encode(proposalFile.TOML()) + if err != nil { + return err + } + + fmt.Printf("Proposal created successfully at path %s", filepath) + return nil +} + +func fetchPublicKey(beaconID string, l log.Logger, address string, targetSch *crypto.Scheme) (*drand.Participant, error) { + parts := strings.Split(address, "https://") + tls := len(parts) > 1 + var peer net.Peer + if tls { + peer = net.CreatePeer(parts[1], tls) + } else { + peer = net.CreatePeer(address, tls) + } + client := net.NewGrpcClient(l) + identity, err := client.GetIdentity(context.Background(), peer, &drand.IdentityRequest{Metadata: &common2.Metadata{BeaconID: beaconID}}) + if err != nil { + return nil, fmt.Errorf("could not fetch public key for %s: %v", address, err) + } + + if identity.SchemeName != targetSch.Name { + return nil, key.ErrInvalidKeyScheme + } + + part := &drand.Participant{ + Address: identity.Address, + Tls: identity.Tls, + Key: identity.Key, + Signature: identity.Signature, + } + + id, err := key.IdentityFromProto(part, targetSch) + if err != nil { + return nil, err + } + l.Debugw("Validating signature for", id.Addr, "scheme", targetSch.Name) + if err := id.ValidSignature(); err != nil { + return nil, key.ErrInvalidKeyScheme + } + + return part, nil +} diff --git a/internal/dkg_cli_test.go b/internal/dkg_cli_test.go new file mode 100644 index 0000000..9cd61b8 --- /dev/null +++ b/internal/dkg_cli_test.go @@ -0,0 +1,66 @@ +package drand + +import ( + "encoding/hex" + "testing" + "time" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/drand/drand/common/key" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/dkg" + "github.com/drand/drand/protobuf/drand" +) + +func TestDKGPrintModelConversion(t *testing.T) { + now := time.Date(2023, 1, 1, 1, 1, 2, 0, time.UTC) + genesisSeed, err := hex.DecodeString("deadbeef") + require.NoError(t, err) + entry := drand.DKGEntry{ + BeaconID: "banana", + State: uint32(dkg.Complete), + Epoch: 3, + Threshold: 2, + Timeout: timestamppb.New(now), + GenesisTime: timestamppb.New(now.Add(1 * time.Minute)), + TransitionTime: timestamppb.New(now.Add(2 * time.Minute)), + GenesisSeed: genesisSeed, + Leader: NewParticipant("alice"), + Remaining: []*drand.Participant{NewParticipant("alice"), NewParticipant("bob"), NewParticipant("carol")}, + Joining: []*drand.Participant{NewParticipant("david")}, + Leaving: nil, + Acceptors: nil, + Rejectors: nil, + FinalGroup: []string{"alice", "bob", "carol"}, + } + printModel := convert(&entry) + + require.Equal(t, "banana", printModel.BeaconID) + require.Equal(t, "Complete", printModel.Status) + require.Equal(t, "3", printModel.Epoch) + require.Equal(t, "2", printModel.Threshold) + require.Equal(t, "2023-01-01T01:01:02Z", printModel.Timeout) + require.Equal(t, "2023-01-01T01:02:02Z", printModel.GenesisTime) + require.Equal(t, "2023-01-01T01:03:02Z", printModel.TransitionTime) + require.Equal(t, "deadbeef", printModel.GenesisSeed) + require.Equal(t, "alice", printModel.Leader) + require.Equal(t, "[\n\talice,\n\tbob,\n\tcarol,\n]", printModel.Remaining) + require.Equal(t, `[david]`, printModel.Joining) + require.Equal(t, "[]", printModel.Leaving) + require.Equal(t, "[]", printModel.Accepted) + require.Equal(t, "[]", printModel.Rejected) + require.Equal(t, "[\n\talice,\n\tbob,\n\tcarol,\n]", printModel.FinalGroup) +} + +func NewParticipant(name string) *drand.Participant { + sch, _ := crypto.GetSchemeFromEnv() + k, _ := key.NewKeyPair(name, sch) + pk, _ := k.Public.Key.MarshalBinary() + return &drand.Participant{ + Address: name, + Tls: false, + Key: pk, + } +} diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go new file mode 100644 index 0000000..edd19f5 --- /dev/null +++ b/internal/lib/cli_test.go @@ -0,0 +1,170 @@ +package lib + +import ( + "bytes" + "context" + "encoding/hex" + "errors" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" + + client2 "github.com/drand/drand/client" + httpmock "github.com/drand/drand/client/test/http/mock" + commonutils "github.com/drand/drand/common" + "github.com/drand/drand/common/log" + "github.com/drand/drand/crypto" + "github.com/drand/drand/internal/test/mock" + "github.com/drand/drand/internal/test/testlogger" +) + +var ( + opts []client2.Option +) + +const ( + fakeGossipRelayAddr = "/ip4/8.8.8.8/tcp/9/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" + fakeChainHash = "6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83" +) + +func mockAction(c *cli.Context) error { + _, err := Create(c, false, opts...) + return err +} + +func run(l log.Logger, args []string) error { + app := cli.NewApp() + app.Name = "mock-client" + app.Flags = ClientFlags + app.Action = func(c *cli.Context) error { + c.Context = log.ToContext(c.Context, l) + return mockAction(c) + } + + return app.Run(args) +} + +func TestClientLib(t *testing.T) { + opts = []client2.Option{} + lg := testlogger.New(t) + err := run(lg, []string{"mock-client"}) + if err == nil { + t.Fatal("need to specify a connection method.", err) + } + + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) + go grpcLis.Start() + defer grpcLis.Stop(context.Background()) + + args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} + err = run(lg, args) + if err != nil { + t.Fatal("GRPC should work", err) + } + + args = []string{"mock-client", "--url", "https://" + addr} + err = run(lg, args) + if err == nil { + t.Fatal("http needs insecure or hash", err) + } + + args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err != nil { + t.Fatal("http should construct", err) + } + + args = []string{"mock-client", "--relay", fakeGossipRelayAddr} + err = run(lg, args) + if err == nil { + t.Fatal("relays need URL to get chain info and hash", err) + } + + args = []string{"mock-client", "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err == nil { + t.Fatal("relays need URL to get chain info and hash", err) + } + + args = []string{"mock-client", "--url", "http://" + addr, "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err != nil { + t.Fatal("unable to get relay to work", err) + } +} + +func TestClientLibGroupConfTOML(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) + if err != nil { + t.Fatal(err) + } +} + +func TestClientLibGroupConfJSON(t *testing.T) { + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + var b bytes.Buffer + require.NoError(t, info.ToJSON(&b, nil)) + + infoPath := filepath.Join(t.TempDir(), "info.json") + + err = os.WriteFile(infoPath, b.Bytes(), 0644) + if err != nil { + t.Fatal(err) + } + + err = run(lg, []string{"mock-client", "--url", "http://" + addr, "--group-conf", infoPath}) + if err != nil { + t.Fatal(err) + } +} + +func TestClientLibChainHashOverrideError(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{ + "mock-client", + "--relay", + fakeGossipRelayAddr, + "--group-conf", + groupTOMLPath(), + "--hash", + fakeChainHash, + }) + if !errors.Is(err, commonutils.ErrInvalidChainHash) { + t.Fatal("expected error from mismatched chain hashes. Got: ", err) + } +} + +func TestClientLibListenPort(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) + if err != nil { + t.Fatal(err) + } +} + +func groupTOMLPath() string { + _, file, _, ok := runtime.Caller(0) + if !ok { + return "" + } + return filepath.Join(filepath.Dir(file), "..", "..", "internal", "test", "default.toml") +} diff --git a/internal/proposal_file.go b/internal/proposal_file.go new file mode 100644 index 0000000..64356b8 --- /dev/null +++ b/internal/proposal_file.go @@ -0,0 +1,124 @@ +package drand + +import ( + "encoding/hex" + + "github.com/BurntSushi/toml" + + "github.com/drand/drand/protobuf/drand" +) + +type ProposalFileFormat struct { + Joining []*TomlParticipant + Leaving []*TomlParticipant + Remaining []*TomlParticipant +} + +type ProposalFile struct { + Joining []*drand.Participant + Leaving []*drand.Participant + Remaining []*drand.Participant +} + +func ParseProposalFile(filepath string) (*ProposalFile, error) { + proposalFile := ProposalFileFormat{} + _, err := toml.DecodeFile(filepath, &proposalFile) + + if err != nil { + return nil, err + } + + return &ProposalFile{ + Joining: proposalFile.Joiners(), + Leaving: proposalFile.Leavers(), + Remaining: proposalFile.Remainers(), + }, nil +} + +func (p *ProposalFileFormat) Joiners() []*drand.Participant { + out := make([]*drand.Participant, len(p.Joining)) + + for i, participant := range p.Joining { + out[i] = participant.Into() + } + + return out +} +func (p *ProposalFileFormat) Leavers() []*drand.Participant { + out := make([]*drand.Participant, len(p.Leaving)) + + for i, participant := range p.Leaving { + out[i] = participant.Into() + } + + return out +} + +func (p *ProposalFileFormat) Remainers() []*drand.Participant { + out := make([]*drand.Participant, len(p.Remaining)) + + for i, participant := range p.Remaining { + out[i] = participant.Into() + } + + return out +} + +type TomlParticipant struct { + Address string + TLS bool + Key string + Signature string +} + +func (t *TomlParticipant) Into() *drand.Participant { + return &drand.Participant{ + Address: t.Address, + Tls: t.TLS, + Key: decodeHexOrPanic(t.Key), + Signature: decodeHexOrPanic(t.Signature), + } +} + +func (p *ProposalFile) TOML() ProposalFileFormat { + out := ProposalFileFormat{} + + for _, j := range p.Joining { + p := encode(j) + out.Joining = append(out.Joining, &p) + } + + for _, r := range p.Remaining { + p := encode(r) + out.Remaining = append(out.Remaining, &p) + } + + for _, l := range p.Leaving { + p := encode(l) + out.Leaving = append(out.Leaving, &p) + } + + return out +} + +func encode(p *drand.Participant) TomlParticipant { + return TomlParticipant{ + Address: p.Address, + TLS: p.Tls, + Key: hex.EncodeToString(p.Key), + Signature: hex.EncodeToString(p.Signature), + } +} + +func decodeHexOrPanic(input string) []byte { + // input lengths are u8 instead of hex, so /2 + byteLength := len(input) / 2 + out := make([]byte, byteLength) + + _, err := hex.Decode(out, []byte(input)) + if err != nil { + panic("Invalid hex in proposal file!") + } + + return out +} diff --git a/internal/proposal_file_test.go b/internal/proposal_file_test.go new file mode 100644 index 0000000..9cd5422 --- /dev/null +++ b/internal/proposal_file_test.go @@ -0,0 +1,70 @@ +package drand + +import ( + "bytes" + "encoding/hex" + "errors" + + "github.com/BurntSushi/toml" + + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/net" +) + +func generateJoiningProposal(l log.Logger, beaconID string, joining []string) (string, error) { + return generateProposal(l, beaconID, joining, []string{}, []string{}) +} + +func generateProposal(l log.Logger, beaconID string, joining, remaining, leaving []string) (string, error) { + if len(joining) == 0 && len(remaining) == 0 && len(leaving) == 0 { + return "", errors.New("you must fill at least one of the ") + } + + extractParticipants := func(addrs []string) ([]*TomlParticipant, error) { + var participants []*TomlParticipant + for _, addr := range addrs { + client, err := net.NewControlClient(l, addr) + if err != nil { + return nil, err + } + res, err := client.PublicKey(beaconID) + if err != nil { + return nil, err + } + participants = append(participants, &TomlParticipant{ + Address: res.Addr, + TLS: res.Tls, + Key: hex.EncodeToString(res.PubKey), + Signature: hex.EncodeToString(res.Signature), + }) + } + return participants, nil + } + + joiners, err := extractParticipants(joining) + if err != nil { + return "", err + } + remainers, err := extractParticipants(remaining) + if err != nil { + return "", err + } + leavers, err := extractParticipants(leaving) + if err != nil { + return "", err + } + + outputFile := ProposalFileFormat{ + Joining: joiners, + Leaving: leavers, + Remaining: remainers, + } + + b := bytes.NewBufferString("") + err = toml.NewEncoder(b).Encode(outputFile) + if err != nil { + return "", err + } + + return b.String(), nil +} diff --git a/internal/public.go b/internal/public.go new file mode 100644 index 0000000..6747147 --- /dev/null +++ b/internal/public.go @@ -0,0 +1,116 @@ +package drand + +import ( + "encoding/hex" + "errors" + "fmt" + gonet "net" + "os" + + "github.com/urfave/cli/v2" + + "github.com/drand/drand/client/grpc" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/internal/core" + "github.com/drand/drand/internal/net" +) + +func getPublicRandomness(c *cli.Context, lg log.Logger) error { + if !c.Args().Present() { + return errors.New("get public command takes a group file as argument") + } + + certPath := "" + if c.IsSet(tlsCertFlag.Name) { + certPath = c.String(tlsCertFlag.Name) + } + + ids, err := getNodes(c) + if err != nil { + return err + } + + group, err := getGroup(c) + if err != nil { + return err + } + if group.PublicKey == nil { + return errors.New("drand: group file must contain the distributed public key") + } + + info := chain.NewChainInfo(lg, group) + + var resp client.Result + var foundCorrect bool + for _, id := range ids { + grpcClient, err := grpc.New(lg, id.Addr, certPath, !id.TLS, info.Hash()) + if err != nil { + fmt.Fprintf(os.Stderr, "drand: could not connect to %s: %s\n", id.Addr, err) + break + } + + resp, err = grpcClient.Get(c.Context, uint64(c.Int(roundFlag.Name))) + + if err == nil { + foundCorrect = true + if c.Bool(verboseFlag.Name) { + fmt.Fprintf(c.App.Writer, "drand: public randomness retrieved from %s\n", id.Addr) + } + break + } + fmt.Fprintf(os.Stderr, "drand: could not get public randomness from %s: %s\n", id.Addr, err) + } + if !foundCorrect { + return errors.New("drand: could not verify randomness") + } + + return printJSON(c.App.Writer, resp) +} + +func getChainInfo(c *cli.Context, lg log.Logger) error { + ctx := c.Context + var err error + chainHash := make([]byte, 0) + if c.IsSet(hashInfoNoReq.Name) { + if chainHash, err = hex.DecodeString(c.String(hashInfoNoReq.Name)); err != nil { + return fmt.Errorf("invalid chain hash given: %w", err) + } + } + + grpcClient := core.NewGrpcClient(lg, chainHash) + if c.IsSet(tlsCertFlag.Name) { + defaultManager := net.NewCertManager(lg) + certPath := c.String(tlsCertFlag.Name) + if err := defaultManager.Add(certPath); err != nil { + return err + } + grpcClient = core.NewGrpcClientFromCert(lg, chainHash, defaultManager) + } + var ci *chain.Info + for _, addr := range c.Args().Slice() { + _, _, err := gonet.SplitHostPort(addr) + if err != nil { + return fmt.Errorf("invalid address given: %w", err) + } + ci, err = grpcClient.ChainInfo(ctx, net.CreatePeer(addr, !c.Bool("tls-disable"))) + if err == nil { + break + } + fmt.Fprintf(os.Stderr, "drand: error fetching distributed key from %s : %s\n", + addr, err) + } + if ci == nil { + return errors.New("drand: can't retrieve dist. key from any nodes") + } + return printChainInfo(c, ci) +} + +func printChainInfo(c *cli.Context, ci *chain.Info) error { + if c.Bool(hashOnly.Name) { + fmt.Fprintf(c.App.Writer, "%s\n", hex.EncodeToString(ci.Hash())) + return nil + } + return printJSON(c.App.Writer, ci.ToProto(nil)) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..f23f558 --- /dev/null +++ b/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "os" + + "github.com/drand/drand/internal/drand-cli" +) + +func main() { + app := drand.CLI() + if err := app.Run(os.Args); err != nil { + fmt.Printf("%+v\n", err) + os.Exit(1) + } +} From e4af1e9862ffd6dea91ffc4abb41163ad9f57feb Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 31 Aug 2023 18:11:41 +0200 Subject: [PATCH 02/28] some more wip --- client/aggregator_test.go | 2 +- client/cache_test.go | 2 +- client/client.go | 13 +- client/client_test.go | 4 +- client/doc.go | 6 +- client/empty.go | 2 +- client/empty_test.go | 4 +- client/grpc/client.go | 20 +- client/grpc/client_test.go | 4 +- client/http/http.go | 39 +- client/http/http_test.go | 2 +- client/http/metric.go | 4 +- client/lp2p/client.go | 2 +- client/lp2p/client_test.go | 8 +- client/lp2p/validator.go | 18 +- client/lp2p/validator_test.go | 6 +- client/metric.go | 4 +- client/mock/mock.go | 2 +- client/optimizing.go | 2 +- client/optimizing_test.go | 2 +- client/poll.go | 2 +- client/random.go | 18 +- client/test/http/mock/httpserver.go | 8 +- client/utils_test.go | 2 +- client/verify_test.go | 2 +- cmd/main.go | 2 +- internal/cli.go | 883 +--------------------------- internal/cli_test.go | 16 +- internal/control.go | 500 +--------------- internal/daemon.go | 80 --- internal/dkg_cli.go | 789 ------------------------- internal/dkg_cli_test.go | 66 --- internal/lib/cli_test.go | 4 +- internal/proposal_file_test.go | 3 +- internal/public.go | 116 ---- main.go | 2 +- 36 files changed, 91 insertions(+), 2548 deletions(-) delete mode 100644 internal/daemon.go delete mode 100644 internal/dkg_cli.go delete mode 100644 internal/dkg_cli_test.go delete mode 100644 internal/public.go diff --git a/client/aggregator_test.go b/client/aggregator_test.go index 1509ab2..d70b8fe 100644 --- a/client/aggregator_test.go +++ b/client/aggregator_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" + "github.com/drand/drand-cli/internal/test/testlogger" clientMock "github.com/drand/drand/client/mock" "github.com/drand/drand/client/test/result/mock" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/test/testlogger" ) func TestAggregatorClose(t *testing.T) { diff --git a/client/cache_test.go b/client/cache_test.go index ebf3f38..c80dcc3 100644 --- a/client/cache_test.go +++ b/client/cache_test.go @@ -5,10 +5,10 @@ import ( "sync" "testing" + "github.com/drand/drand-cli/internal/test/testlogger" clientMock "github.com/drand/drand/client/mock" "github.com/drand/drand/client/test/result/mock" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/test/testlogger" ) func TestCacheGet(t *testing.T) { diff --git a/client/client.go b/client/client.go index 10cc998..a63210c 100644 --- a/client/client.go +++ b/client/client.go @@ -13,7 +13,6 @@ import ( "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/metrics" ) const clientStartupTimeoutDefault = time.Second * 5 @@ -108,7 +107,7 @@ func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Cl wa.Start() - return attachMetrics(cfg, c) + return c, nil } //nolint:lll // This function has nicely named parameters, so it's long. @@ -152,16 +151,6 @@ func makeWatcherClient(cfg *clientConfig, cache Cache) (client.Client, error) { return &watcherClient{ec, w}, nil } -func attachMetrics(cfg *clientConfig, c client.Client) (client.Client, error) { - if cfg.prometheus != nil { - if err := metrics.RegisterClientMetrics(cfg.prometheus); err != nil { - return nil, err - } - return newWatchLatencyMetricClient(c, cfg.chainInfo), nil - } - return c, nil -} - type clientConfig struct { // clients is the set of options for fetching randomness clients []client.Client diff --git a/client/client_test.go b/client/client_test.go index 4c4fe3d..4a968d6 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -9,6 +9,8 @@ import ( clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/test" + "github.com/drand/drand-cli/internal/test/testlogger" client2 "github.com/drand/drand/client" "github.com/drand/drand/client/http" clientMock "github.com/drand/drand/client/mock" @@ -17,8 +19,6 @@ import ( "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test" - "github.com/drand/drand/internal/test/testlogger" ) func TestClientConstraints(t *testing.T) { diff --git a/client/doc.go b/client/doc.go index 6ba72e3..bf64187 100644 --- a/client/doc.go +++ b/client/doc.go @@ -35,9 +35,9 @@ Example: The "From" option allows you to specify clients that work over particular transports. HTTP, gRPC and libp2p PubSub clients are provided in drand's -subpackages https://pkg.go.dev/github.com/drand/drand/internal/client/http, -https://pkg.go.dev/github.com/drand/drand/internal/client/grpc and -https://pkg.go.dev/github.com/drand/drand/internal/lp2p/clientlp2p/client +subpackages https://pkg.go.dev/github.com/drand/drand-cli/internal/client/http, +https://pkg.go.dev/github.com/drand/drand-cli/internal/client/grpc and +https://pkg.go.dev/github.com/drand/drand-cli/internal/lp2p/clientlp2p/client respectively. Note that you are not restricted to just one client. You can use multiple clients of the same type or of different types. The base client will periodically "speed test" it's clients, failover, cache results and aggregate diff --git a/client/empty.go b/client/empty.go index 7c1d24f..00a0581 100644 --- a/client/empty.go +++ b/client/empty.go @@ -4,10 +4,10 @@ import ( "context" "time" + "github.com/drand/drand-cli/internal/chain" "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/chain" ) const emptyClientStringerValue = "EmptyClient" diff --git a/client/empty_test.go b/client/empty_test.go index 91d5427..f207c79 100644 --- a/client/empty_test.go +++ b/client/empty_test.go @@ -3,11 +3,11 @@ package client import ( "context" "fmt" + commonutils "github.com/drand/drand/common" "testing" "time" chain2 "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/chain" ) func TestEmptyClient(t *testing.T) { @@ -26,7 +26,7 @@ func TestEmptyClient(t *testing.T) { // should be able to retrieve RoundAt now := time.Now() rnd := c.RoundAt(now) - if rnd != chain.CurrentRound(now.Unix(), chainInfo.Period, chainInfo.GenesisTime) { + if rnd != commonutils.CurrentRound(now.Unix(), chainInfo.Period, chainInfo.GenesisTime) { t.Fatal("unexpected RoundAt return value", rnd) } diff --git a/client/grpc/client.go b/client/grpc/client.go index f1b3483..4533fef 100644 --- a/client/grpc/client.go +++ b/client/grpc/client.go @@ -5,6 +5,8 @@ import ( "crypto/tls" "errors" "fmt" + "github.com/drand/drand-cli/client" + commonutils "github.com/drand/drand/common" "time" grpcProm "github.com/grpc-ecosystem/go-grpc-prometheus" @@ -12,11 +14,9 @@ import ( "google.golang.org/grpc/credentials" grpcInsec "google.golang.org/grpc/credentials/insecure" - "github.com/drand/drand/client" chain2 "github.com/drand/drand/common/chain" client2 "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/chain" "github.com/drand/drand/protobuf/common" "github.com/drand/drand/protobuf/drand" ) @@ -32,15 +32,9 @@ type grpcClient struct { } // New creates a drand client backed by a GRPC connection. -func New(l log.Logger, address, certPath string, insecure bool, chainHash []byte) (client2.Client, error) { +func New(l log.Logger, address string, insecure bool, chainHash []byte) (client2.Client, error) { var opts []grpc.DialOption - if certPath != "" { - creds, err := credentials.NewClientTLSFromFile(certPath, "") - if err != nil { - return nil, err - } - opts = append(opts, grpc.WithTransportCredentials(creds)) - } else if insecure { + if insecure { opts = append(opts, grpc.WithTransportCredentials(grpcInsec.NewCredentials())) } else { opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}))) @@ -54,7 +48,7 @@ func New(l log.Logger, address, certPath string, insecure bool, chainHash []byte return nil, err } - return &grpcClient{address, chainHash, NewPublicClient(conn), conn, l}, nil + return &grpcClient{address, chainHash, drand.NewPublicClient(conn), conn, l}, nil } func asRD(r *drand.PublicRandResponse) *client.RandomData { @@ -71,7 +65,7 @@ func (g *grpcClient) String() string { return fmt.Sprintf("GRPC(%q)", g.address) } -// Get returns a the randomness at `round` or an error. +// Get returns the randomness at `round` or an error. func (g *grpcClient) Get(ctx context.Context, round uint64) (client2.Result, error) { curr, err := g.client.PublicRand(ctx, &drand.PublicRandRequest{Round: round, Metadata: g.getMetadata()}) if err != nil { @@ -134,7 +128,7 @@ func (g *grpcClient) RoundAt(t time.Time) uint64 { if err != nil { return 0 } - return chain.CurrentRound(t.Unix(), time.Second*time.Duration(info.Period), info.GenesisTime) + return commonutils.CurrentRound(t.Unix(), time.Second*time.Duration(info.Period), info.GenesisTime) } // SetLog configures the client log output diff --git a/client/grpc/client_test.go b/client/grpc/client_test.go index 8d27feb..dbd1266 100644 --- a/client/grpc/client_test.go +++ b/client/grpc/client_test.go @@ -12,9 +12,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/drand/drand-cli/internal/test/mock" + "github.com/drand/drand-cli/internal/test/testlogger" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test/mock" - "github.com/drand/drand/internal/test/testlogger" ) func TestClient(t *testing.T) { diff --git a/client/http/http.go b/client/http/http.go index bb81e92..37e8a1f 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -11,17 +11,11 @@ import ( "strings" "time" - json "github.com/nikkolasg/hexjson" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - - client2 "github.com/drand/drand/client" "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/metrics" + json "github.com/nikkolasg/hexjson" ) var errClientClosed = fmt.Errorf("client closed") @@ -48,7 +42,7 @@ func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transp agent := fmt.Sprintf("drand-client-%s/1.0", path.Base(pn)) c := &httpClient{ root: url, - client: instrumentClient(url, transport), + client: createClient(url, transport), l: l, Agent: agent, done: make(chan struct{}), @@ -83,7 +77,7 @@ func NewWithInfo(l log.Logger, url string, info *chain2.Info, transport nhttp.Ro c := &httpClient{ root: url, chainInfo: info, - client: instrumentClient(url, transport), + client: createClient(url, transport), l: l, Agent: agent, done: make(chan struct{}), @@ -143,35 +137,12 @@ func Ping(ctx context.Context, root string) error { return nil } -// Instruments an HTTP client around a transport -func instrumentClient(url string, transport nhttp.RoundTripper) *nhttp.Client { +// createClient creates an HTTP client around a transport, allows to easily instrument it later +func createClient(url string, transport nhttp.RoundTripper) *nhttp.Client { hc := nhttp.Client{} hc.Timeout = defaultHTTTPTimeout hc.Jar = nhttp.DefaultClient.Jar hc.CheckRedirect = nhttp.DefaultClient.CheckRedirect - urlLabel := prometheus.Labels{"url": url} - - trace := &promhttp.InstrumentTrace{ - DNSStart: func(t float64) { - metrics.ClientDNSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("dns_start").Observe(t) - }, - DNSDone: func(t float64) { - metrics.ClientDNSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("dns_done").Observe(t) - }, - TLSHandshakeStart: func(t float64) { - metrics.ClientTLSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("tls_handshake_start").Observe(t) - }, - TLSHandshakeDone: func(t float64) { - metrics.ClientTLSLatencyVec.MustCurryWith(urlLabel).WithLabelValues("tls_handshake_done").Observe(t) - }, - } - - transport = promhttp.InstrumentRoundTripperInFlight(metrics.ClientInFlight.With(urlLabel), - promhttp.InstrumentRoundTripperCounter(metrics.ClientRequests.MustCurryWith(urlLabel), - promhttp.InstrumentRoundTripperTrace(trace, - promhttp.InstrumentRoundTripperDuration(metrics.ClientLatencyVec.MustCurryWith(urlLabel), - transport)))) - hc.Transport = transport return &hc diff --git a/client/http/http_test.go b/client/http/http_test.go index f5c62f5..35981a1 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -14,10 +14,10 @@ import ( clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/test/testlogger" "github.com/drand/drand/client" "github.com/drand/drand/client/test/http/mock" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test/testlogger" ) func TestHTTPClient(t *testing.T) { diff --git a/client/http/metric.go b/client/http/metric.go index 2180ba9..0ff000a 100644 --- a/client/http/metric.go +++ b/client/http/metric.go @@ -6,9 +6,9 @@ import ( "github.com/prometheus/client_golang/prometheus" + "github.com/drand/drand-cli/internal/chain" + "github.com/drand/drand-cli/internal/metrics" chain2 "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/metrics" ) // MeasureHeartbeats periodically tracks latency observed on a set of HTTP clients diff --git a/client/lp2p/client.go b/client/lp2p/client.go index 9e204eb..70a1294 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -13,11 +13,11 @@ import ( "github.com/multiformats/go-multiaddr" "google.golang.org/protobuf/proto" + "github.com/drand/drand-cli/internal/lp2p" client2 "github.com/drand/drand/client" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/lp2p" "github.com/drand/drand/protobuf/drand" ) diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index d821440..b61e3ec 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -15,16 +15,16 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/lp2p" + "github.com/drand/drand-cli/internal/test" + "github.com/drand/drand-cli/internal/test/mock" + "github.com/drand/drand-cli/internal/test/testlogger" "github.com/drand/drand/client/grpc" dhttp "github.com/drand/drand/client/http" httpmock "github.com/drand/drand/client/test/http/mock" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/lp2p" - "github.com/drand/drand/internal/test" - "github.com/drand/drand/internal/test/mock" - "github.com/drand/drand/internal/test/testlogger" ) func TestGRPCClientTestFunc(t *testing.T) { diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go index 91b1d2b..98bff0f 100644 --- a/client/lp2p/validator.go +++ b/client/lp2p/validator.go @@ -3,6 +3,8 @@ package lp2p import ( "bytes" "context" + "github.com/drand/drand-cli/client" + commonutils "github.com/drand/drand/common" "time" clock "github.com/jonboulle/clockwork" @@ -10,14 +12,12 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "google.golang.org/protobuf/proto" - client2 "github.com/drand/drand/client" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/chain" "github.com/drand/drand/protobuf/drand" ) -func randomnessValidator(info *chain2.Info, cache client2.Cache, c *Client, clk clock.Clock) pubsub.ValidatorEx { +func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk clock.Clock) pubsub.ValidatorEx { return func(ctx context.Context, p peer.ID, m *pubsub.Message) pubsub.ValidationResult { rand := &drand.PublicRandResponse{} err := proto.Unmarshal(m.Data, rand) @@ -35,7 +35,7 @@ func randomnessValidator(info *chain2.Info, cache client2.Cache, c *Client, clk // Unwilling to relay beacons in the future. timeNow := clk.Now() - timeOfRound := chain.TimeOfRound(info.Period, info.GenesisTime, rand.GetRound()) + timeOfRound := commonutils.TimeOfRound(info.Period, info.GenesisTime, rand.GetRound()) if time.Unix(timeOfRound, 0).After(timeNow) { c.log.Warnw("", "gossip validator", "Not validating received randomness due to time of round", @@ -51,21 +51,21 @@ func randomnessValidator(info *chain2.Info, cache client2.Cache, c *Client, clk if cache != nil { if current := cache.TryGet(rand.GetRound()); current != nil { - currentFull, ok := current.(*client2.RandomData) + currentFull, ok := current.(*client.RandomData) if !ok { // Note: this shouldn't happen in practice, but if we have a // degraded cache entry we can't validate the full byte // sequence. - if bytes.Equal(rand.GetSignature(), current.Signature()) { + if bytes.Equal(rand.GetSignature(), current.GetSignature()) { c.log.Warnw("", "gossip validator", "ignore") return pubsub.ValidationIgnore } c.log.Warnw("", "gossip validator", "reject") return pubsub.ValidationReject } - if current.Round() == rand.GetRound() && - bytes.Equal(current.Randomness(), rand.GetRandomness()) && - bytes.Equal(current.Signature(), rand.GetSignature()) && + if current.GetRound() == rand.GetRound() && + bytes.Equal(current.GetRandomness(), rand.GetRandomness()) && + bytes.Equal(current.GetSignature(), rand.GetSignature()) && bytes.Equal(currentFull.PreviousSignature, rand.GetPreviousSignature()) { c.log.Warnw("", "gossip validator", "ignore") return pubsub.ValidationIgnore diff --git a/client/lp2p/validator_test.go b/client/lp2p/validator_test.go index 0cebf36..90fe032 100644 --- a/client/lp2p/validator_test.go +++ b/client/lp2p/validator_test.go @@ -16,13 +16,13 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "google.golang.org/protobuf/proto" + "github.com/drand/drand-cli/internal/chain" + "github.com/drand/drand-cli/internal/test" + "github.com/drand/drand-cli/internal/test/testlogger" "github.com/drand/drand/client" "github.com/drand/drand/client/test/cache" chain2 "github.com/drand/drand/common/chain" dcrypto "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/test" - "github.com/drand/drand/internal/test/testlogger" "github.com/drand/drand/protobuf/drand" ) diff --git a/client/metric.go b/client/metric.go index 254c070..a93a4ab 100644 --- a/client/metric.go +++ b/client/metric.go @@ -4,10 +4,10 @@ import ( "context" "time" + "github.com/drand/drand-cli/internal/chain" + "github.com/drand/drand-cli/internal/metrics" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/metrics" ) func newWatchLatencyMetricClient(base client.Client, info *chain2.Info) client.Client { diff --git a/client/mock/mock.go b/client/mock/mock.go index 4f1afd5..fb6e945 100644 --- a/client/mock/mock.go +++ b/client/mock/mock.go @@ -6,10 +6,10 @@ import ( "sync" "time" + "github.com/drand/drand-cli/internal/chain" "github.com/drand/drand/client/test/result/mock" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/chain" ) // Client provide a mocked client interface diff --git a/client/optimizing.go b/client/optimizing.go index 6fff80d..a8b20d5 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -12,11 +12,11 @@ import ( "github.com/hashicorp/go-multierror" + "github.com/drand/drand-cli/internal/chain" "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/chain" ) const ( diff --git a/client/optimizing_test.go b/client/optimizing_test.go index 67ef8d6..f7e7efb 100644 --- a/client/optimizing_test.go +++ b/client/optimizing_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" + "github.com/drand/drand-cli/internal/test/testlogger" clientMock "github.com/drand/drand/client/mock" "github.com/drand/drand/client/test/result/mock" "github.com/drand/drand/common/client" - "github.com/drand/drand/internal/test/testlogger" ) // waitForSpeedTest waits until all clients have had their initial speed test. diff --git a/client/poll.go b/client/poll.go index b17be23..67bc8a9 100644 --- a/client/poll.go +++ b/client/poll.go @@ -4,10 +4,10 @@ import ( "context" "time" + "github.com/drand/drand-cli/internal/chain" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/chain" ) // PollingWatcher generalizes the `Watch` interface for clients which learn new values diff --git a/client/random.go b/client/random.go index 77cb521..e1d0d47 100644 --- a/client/random.go +++ b/client/random.go @@ -9,17 +9,23 @@ type RandomData struct { PreviousSignature []byte `json:"previous_signature,omitempty"` } -// Round provides access to the round associated with this random data. -func (r *RandomData) Round() uint64 { +// GetRound provides access to the round associated with this random data. +func (r *RandomData) GetRound() uint64 { return r.Rnd } -// Signature provides the signature over this round's randomness -func (r *RandomData) Signature() []byte { +// GetSignature provides the signature over this round's randomness +func (r *RandomData) GetSignature() []byte { return r.Sig } -// Randomness exports the randomness -func (r *RandomData) Randomness() []byte { +// GetPreviousSignature provides the previous signature provided by the beacon, +// if nil, it's most likely using an unchained scheme. +func (r *RandomData) GetPreviousSignature() []byte { + return r.PreviousSignature +} + +// GetRandomness exports the randomness using the legacy SHA256 derivation path +func (r *RandomData) GetRandomness() []byte { return r.Random } diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 64027b4..6a2bca8 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -9,13 +9,13 @@ import ( clock "github.com/jonboulle/clockwork" + "github.com/drand/drand-cli/internal/core" + dhttp "github.com/drand/drand-cli/internal/http" + "github.com/drand/drand-cli/internal/test/mock" + "github.com/drand/drand-cli/internal/test/testlogger" chainCommon "github.com/drand/drand/common/chain" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/core" - dhttp "github.com/drand/drand/internal/http" - "github.com/drand/drand/internal/test/mock" - "github.com/drand/drand/internal/test/testlogger" "github.com/drand/drand/protobuf/drand" ) diff --git a/client/utils_test.go b/client/utils_test.go index a7416e0..9cdffcd 100644 --- a/client/utils_test.go +++ b/client/utils_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/test" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test" ) // fakeChainInfo creates a chain info object for use in tests. diff --git a/client/verify_test.go b/client/verify_test.go index 5b6a0c9..624039b 100644 --- a/client/verify_test.go +++ b/client/verify_test.go @@ -7,13 +7,13 @@ import ( "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/test/testlogger" client2 "github.com/drand/drand/client" clientMock "github.com/drand/drand/client/mock" "github.com/drand/drand/client/test/result/mock" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test/testlogger" ) func mockClientWithVerifiableResults(ctx context.Context, t *testing.T, l log.Logger, n int) (client.Client, []mock.Result) { diff --git a/cmd/main.go b/cmd/main.go index e85f19a..1f51568 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,10 +12,10 @@ import ( "github.com/prometheus/client_golang/prometheus/push" "github.com/urfave/cli/v2" + "github.com/drand/drand-cli/internal/lib" "github.com/drand/drand/client" "github.com/drand/drand/common" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/lib" ) // Automatically set through -ldflags diff --git a/internal/cli.go b/internal/cli.go index 6a04369..f298173 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - gonet "net" "os" "path" "path/filepath" @@ -22,16 +21,14 @@ import ( "github.com/BurntSushi/toml" "github.com/urfave/cli/v2" + "github.com/drand/drand-cli/internal/core" + "github.com/drand/drand-cli/internal/core/migration" + "github.com/drand/drand-cli/internal/fs" + "github.com/drand/drand-cli/internal/net" "github.com/drand/drand/common" "github.com/drand/drand/common/key" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/chain/boltdb" - "github.com/drand/drand/internal/core" - "github.com/drand/drand/internal/core/migration" - "github.com/drand/drand/internal/fs" - "github.com/drand/drand/internal/net" common2 "github.com/drand/drand/protobuf/common" "github.com/drand/drand/protobuf/drand" ) @@ -52,82 +49,12 @@ func banner(w io.Writer) { _, _ = fmt.Fprintf(w, "drand %s (date %v, commit %v)\n", version.String(), buildDate, gitCommit) } -var folderFlag = &cli.StringFlag{ - Name: "folder", - Value: core.DefaultConfigFolder(), - Usage: "Folder to keep all drand cryptographic information, with absolute path.", - EnvVars: []string{"DRAND_FOLDER"}, -} - var verboseFlag = &cli.BoolFlag{ Name: "verbose", Usage: "If set, verbosity is at the debug level", EnvVars: []string{"DRAND_VERBOSE"}, } -var tlsCertFlag = &cli.StringFlag{ - Name: "tls-cert", - Usage: "Set the TLS certificate chain (in PEM format) for this drand node. " + - "The certificates have to be specified as a list of whitespace-separated file paths. " + - "This parameter is required by default and can only be omitted if the --tls-disable flag is used.", - EnvVars: []string{"DRAND_TLS_CERT"}, -} - -var tlsKeyFlag = &cli.StringFlag{ - Name: "tls-key", - Usage: "Set the TLS private key (in PEM format) for this drand node. " + - "The key has to be specified as a file path. " + - "This parameter is required by default and can only be omitted if the --tls-disable flag is used.", - EnvVars: []string{"DRAND_TLS_KEY"}, -} - -var insecureFlag = &cli.BoolFlag{ - Name: "tls-disable", - Aliases: []string{"insecure"}, - Usage: "Disable TLS for all communications (not recommended).", - EnvVars: []string{"DRAND_TLS_DISABLE", "DRAND_INSECURE"}, -} - -var controlFlag = &cli.StringFlag{ - Name: "control", - Usage: "Set the port you want to listen to for control port commands. If not specified, we will use the default value.", - Value: "8888", - EnvVars: []string{"DRAND_CONTROL"}, -} - -var metricsFlag = &cli.StringFlag{ - Name: "metrics", - Usage: "Launch a metrics server at the specified (host:)port.", - 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.", - EnvVars: []string{"DRAND_PRIVATE_LISTEN"}, -} - -var pubListenFlag = &cli.StringFlag{ - Name: "public-listen", - Usage: "Set the listening (binding) address of the public API. Useful if you have some kind of proxy.", - EnvVars: []string{"DRAND_PUBLIC_LISTEN"}, -} - var nodeFlag = &cli.StringFlag{ Name: "nodes", Usage: "Contact the nodes at the given list of whitespace-separated addresses which have to be present in group.toml.", @@ -141,161 +68,12 @@ var roundFlag = &cli.IntFlag{ EnvVars: []string{"DRAND_ROUND"}, } -var certsDirFlag = &cli.StringFlag{ - Name: "certs-dir", - Usage: "directory containing trusted certificates (PEM format). Useful for testing and self signed certificates", - EnvVars: []string{"DRAND_CERTS_DIR"}, -} - -var outFlag = &cli.StringFlag{ - Name: "out", - Usage: "save the group file into a separate file instead of stdout", - EnvVars: []string{"DRAND_OUT"}, -} - -var backupOutFlag = &cli.StringFlag{ - Name: "out", - Usage: "the filepath to save the backup to", -} - -var periodFlag = &cli.StringFlag{ - Name: "period", - Usage: "period to set when doing a setup", - EnvVars: []string{"DRAND_PERIOD"}, -} - -var catchupPeriodFlag = &cli.StringFlag{ - Name: "catchup-period", - Usage: "Minimum period while in catchup. Set only by the leader of share / reshares", - Value: "0s", - EnvVars: []string{"DRAND_CATCHUP_PERIOD"}, -} - -var thresholdFlag = &cli.IntFlag{ - Name: "threshold", - Usage: "threshold to use for the DKG", - EnvVars: []string{"DRAND_THRESHOLD"}, -} - -// TODO (dlsniper): This flag is a duplicate name of the nodeFlag. Should change the name. -var shareNodeFlag = &cli.IntFlag{ - Name: "nodes", - Usage: "number of nodes expected", - EnvVars: []string{"DRAND_NODES"}, -} - -var transitionFlag = &cli.BoolFlag{ - Name: "reshare", - Aliases: []string{"transition"}, - Usage: "When set, this flag indicates the share operation is a resharing. " + - "The node will use the currently stored group as the basis for the resharing", - EnvVars: []string{"DRAND_TRANSITION_FLAG"}, -} - -var forceFlag = &cli.BoolFlag{ - Name: "force", - Aliases: []string{"f"}, - Usage: "When set, this flag forces the daemon to start a new reshare operation. " + - "By default, it does not allow to restart one", - EnvVars: []string{"DRAND_FORCE"}, -} - -// secretFlag is the "manual" security when the "leader"/coordinator creates the -// group: every participant must know this secret. It is not a consensus, not -// perfect, but since all members are known after the protocol, and members can -// decide to redo the setup, it works in practice well enough. -// TODO Add a manual check when the group is created so the user manually ACK. -var secretFlag = &cli.StringFlag{ - Name: "secret-file", - Usage: "Specify the secret to use when doing the share so the leader knows you are an eligible potential participant." + - " must be at least 32 characters.", - EnvVars: []string{"DRAND_SECRET_FILE"}, -} - -var connectFlag = &cli.StringFlag{ - Name: "connect", - Usage: "Address of the coordinator that will assemble the public keys and start the DKG", - EnvVars: []string{"DRAND_CONNECT"}, -} - -var leaderFlag = &cli.BoolFlag{ - Name: "leader", - Usage: "Specify if this node should act as the leader for setting up the group", - EnvVars: []string{"DRAND_LEADER"}, -} - -var beaconOffset = &cli.IntFlag{ - Name: "beacon-delay", - Usage: "Leader uses this flag to specify the genesis time or transition time as a delay from when " + - " group is ready to run the share protocol", - EnvVars: []string{"DRAND_BEACON_DELAY"}, -} - -var oldGroupFlag = &cli.StringFlag{ - Name: "from", - Usage: "Old group.toml path to specify when a new node wishes to participate " + - "in a resharing protocol. This flag is optional in case a node is already" + - "included in the current DKG.", - EnvVars: []string{"DRAND_FROM"}, -} - -var proposalFlag = &cli.StringFlag{ - Name: "proposal", - Usage: "Path to a toml file specifying the leavers, joiners and remainers for a network proposal", - EnvVars: []string{"DRAND_PROPOSAL_PATH"}, -} - -var skipValidationFlag = &cli.BoolFlag{ - Name: "skipValidation", - Usage: "skips bls verification of beacon rounds for faster catchup.", - EnvVars: []string{"DRAND_SKIP_VALIDATION"}, -} - -var timeoutFlag = &cli.StringFlag{ - Name: "timeout", - Usage: fmt.Sprintf("Timeout to use during the DKG, in string format. Default is %s", core.DefaultDKGPhaseTimeout), - EnvVars: []string{"DRAND_TIMEOUT"}, -} - -var pushFlag = &cli.BoolFlag{ - Name: "push", - Usage: "Push mode forces the daemon to start making beacon requests to the other node, " + - "instead of waiting the other nodes contact it to catch-up on the round", - EnvVars: []string{"DRAND_PUSH"}, -} - -var sourceFlag = &cli.StringFlag{ - Name: "source", - Usage: "Source flag allows to provide an executable which output will be used as additional entropy during resharing step.", - EnvVars: []string{"DRAND_SOURCE"}, -} - -var userEntropyOnlyFlag = &cli.BoolFlag{ - Name: "user-source-only", - Usage: "user-source-only flag used with the source flag allows to only use the user's entropy to pick the dkg secret " + - "(won't be mixed with crypto/rand). Should be used for reproducibility and debbuging purposes.", - EnvVars: []string{"DRAND_USER_SOURCE_ONLY"}, -} - -var groupFlag = &cli.StringFlag{ - Name: "group", - Usage: "Test connections to nodes listed in the group", - EnvVars: []string{"DRAND_GROUP"}, -} - var hashOnly = &cli.BoolFlag{ Name: "hash", Usage: "Only print the hash of the group file", EnvVars: []string{"DRAND_HASH"}, } -var hashInfoReq = &cli.StringFlag{ - Name: "chain-hash", - Usage: "The hash of the chain info, used to validate integrity of the received group info", - Required: true, - EnvVars: []string{"DRAND_CHAIN_HASH"}, -} - // TODO (DLSNIPER): This is a duplicate of the hashInfoReq. Should these be merged into a single flag? var hashInfoNoReq = &cli.StringFlag{ Name: "chain-hash", @@ -303,38 +81,6 @@ var hashInfoNoReq = &cli.StringFlag{ EnvVars: []string{"DRAND_CHAIN_HASH"}, } -// using a simple string flag because the StringSliceFlag is not intuitive -// see https://github.com/urfave/cli/issues/62 -var syncNodeFlag = &cli.StringFlag{ - Name: "sync-nodes", - Usage: ",<...> of (multiple) reachable drand daemon(s). " + - "When checking our local database, using our local daemon address will result in a dry run.", - Required: true, - EnvVars: []string{"DRAND_SYNC_NODES"}, -} - -var followFlag = &cli.BoolFlag{ - Name: "follow", - Usage: "Indicates whether we want to follow another daemon, if not we perform a check of our local DB. " + - "Requires to specify the chain-hash using the '" + hashInfoNoReq.Name + "' flag.", - EnvVars: []string{"DRAND_FOLLOW"}, -} - -var upToFlag = &cli.IntFlag{ - Name: "up-to", - Usage: "Specify a round at which the drand daemon will stop syncing the chain, " + - "typically used to bootstrap a new node in chained mode", - Value: 0, - EnvVars: []string{"DRAND_UP_TO"}, -} - -var schemeFlag = &cli.StringFlag{ - Name: "scheme", - Usage: "Indicates a set of values drand will use to configure the randomness generation process", - Value: crypto.DefaultSchemeID, - EnvVars: []string{"DRAND_SCHEME"}, -} - var jsonFlag = &cli.BoolFlag{ Name: "json", Usage: "Set the output as json format", @@ -347,6 +93,7 @@ var beaconIDFlag = &cli.StringFlag{ Value: "", EnvVars: []string{"DRAND_ID"}, } + var listIdsFlag = &cli.BoolFlag{ Name: "list-ids", Usage: "Indicates if it only have to list the running beacon ids instead of the statuses.", @@ -361,138 +108,7 @@ var allBeaconsFlag = &cli.BoolFlag{ EnvVars: []string{"DRAND_ALL"}, } -var storageTypeFlag = &cli.StringFlag{ - Name: "db", - Usage: "Which database engine to use. Supported values: bolt, postgres, or memdb.", - Value: "bolt", - EnvVars: []string{"DRAND_DB"}, -} - -var pgDSNFlag = &cli.StringFlag{ - Name: "pg-dsn", - Usage: "PostgreSQL DSN configuration.\n" + - "Supported options are:\n" + - //nolint:lll - "- sslmode: if the SSL connection is disabled or required. Default disabled. See: https://www.postgresql.org/docs/15/libpq-ssl.html#LIBPQ-SSL-PROTECTION\n" + - //nolint:lll - "- connect_timeout: how many seconds before the connection attempt times out. Default 5 (seconds). See: https://www.postgresql.org/docs/15/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT\n" + - "- max-idle: number of maximum idle connections. Default: 2\n" + - "- max-open: number of maximum open connections. Default: 0 - unlimited.\n", - - Value: "postgres://drand:drand@127.0.0.1:5432/drand?sslmode=disable&connect_timeout=5", - EnvVars: []string{"DRAND_PG_DSN"}, -} - -var memDBSizeFlag = &cli.IntFlag{ - Name: "memdb-size", - Usage: "The buffer size for in-memory storage. Must be at least 10. Recommended, 2000 or more", - Value: 2000, - EnvVars: []string{"DRAND_MEMDB_SIZE"}, -} - var appCommands = []*cli.Command{ - dkgCommand, - { - Name: "start", - Usage: "Start the drand daemon.", - Flags: toArray(folderFlag, tlsCertFlag, tlsKeyFlag, - insecureFlag, controlFlag, privListenFlag, pubListenFlag, - metricsFlag, tracesFlag, tracesProbabilityFlag, - certsDirFlag, pushFlag, verboseFlag, oldGroupFlag, - skipValidationFlag, jsonFlag, beaconIDFlag, - storageTypeFlag, pgDSNFlag, memDBSizeFlag), - Action: func(c *cli.Context) error { - banner(c.App.Writer) - l := log.New(nil, logLevel(c), logJSON(c)). - Named("startCmd") - return startCmd(c, l) - }, - Before: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("runMigrationCmd") - return runMigration(c, l) - }, - }, - { - Name: "stop", - Usage: "Stop the drand daemon.\n", - Flags: toArray(controlFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - banner(c.App.Writer) - l := log.New(nil, logLevel(c), logJSON(c)). - Named("stopDaemon") - return stopDaemon(c, l) - }, - }, - { - Name: "share", - Usage: "Launch a sharing protocol.", - Flags: toArray(insecureFlag, controlFlag, oldGroupFlag, - timeoutFlag, sourceFlag, userEntropyOnlyFlag, secretFlag, - periodFlag, shareNodeFlag, thresholdFlag, connectFlag, outFlag, - leaderFlag, beaconOffset, transitionFlag, forceFlag, catchupPeriodFlag, - schemeFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - banner(c.App.Writer) - return deprecatedShareCommand(c) - }, - }, - { - Name: "load", - Usage: "Launch a sharing protocol from filesystem", - Flags: toArray(controlFlag, beaconIDFlag, insecureFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("loadCmd") - return loadCmd(c, l) - }, - }, - { - Name: "sync", - Usage: "sync your local randomness chain with other nodes and validate your local beacon chain. To follow a " + - "remote node, it requires the use of the '" + followFlag.Name + "' flag.", - Flags: toArray(folderFlag, controlFlag, hashInfoNoReq, syncNodeFlag, - tlsCertFlag, insecureFlag, upToFlag, beaconIDFlag, followFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("syncCmd") - return syncCmd(c, l) - }, - }, - { - Name: "generate-keypair", - Usage: "Generate the longterm keypair (drand.private, drand.public) " + - "for this node, and load it on the drand daemon if it is up and running.\n", - ArgsUsage: "
is the address other nodes will be able to contact this node on (specified as 'private-listen' to the daemon)", - Flags: toArray(controlFlag, folderFlag, insecureFlag, beaconIDFlag, schemeFlag), - Action: func(c *cli.Context) error { - banner(c.App.Writer) - l := log.New(nil, logLevel(c), logJSON(c)). - Named("generateKeyPairCmd") - - err := keygenCmd(c, l) - - // If keys were generated successfully, daemon needs to load them - // In other to load them, we run LoadBeacon cmd. - // - // TIP: If an error is found, it may indicate daemon is not running. If that is the case, keys will be loaded - // on drand startup. - if err == nil { - err2 := loadCmd(c, l) - if err2 != nil { - fmt.Fprintf(os.Stdout, "Keys couldn't be loaded on drand daemon. If it is not running, "+ - "these new keys will be loaded on startup. Err: %s\n", err2) - } - } - return err - }, - Before: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("generateKeyPairCmd") - return checkMigration(c, l) - }, - }, - { Name: "get", Usage: "get allows for public information retrieval from a remote " + @@ -507,7 +123,7 @@ var appCommands = []*cli.Command{ "beacon via TLS and falls back to plaintext communication " + "if the contacted node has not activated TLS in which case " + "it prints a warning.\n", - Flags: toArray(tlsCertFlag, insecureFlag, roundFlag, nodeFlag), + Flags: toArray(roundFlag, nodeFlag), Action: func(c *cli.Context) error { l := log.New(nil, logLevel(c), logJSON(c)). Named("getPublicRandomness") @@ -518,7 +134,7 @@ var appCommands = []*cli.Command{ Name: "chain-info", Usage: "Get the binding chain information that this node participates to", ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.", - Flags: toArray(tlsCertFlag, insecureFlag, hashOnly, hashInfoNoReq), + Flags: toArray(hashOnly, hashInfoNoReq), Action: func(c *cli.Context) error { l := log.New(nil, logLevel(c), logJSON(c)). Named("getChainInfo") @@ -531,173 +147,15 @@ var appCommands = []*cli.Command{ Name: "util", Usage: "Multiple commands of utility functions, such as reseting a state, checking the connection of a peer...", Subcommands: []*cli.Command{ - { - Name: "check", - Usage: "Check node at the given `ADDRESS` (you can put multiple ones)" + - " in the group for accessibility over the gRPC communication. If the node " + - " is not running behind TLS, you need to pass the tls-disable flag. You can " + - "also check a whole group's connectivity with the group flag.", - Flags: toArray(groupFlag, certsDirFlag, insecureFlag, verboseFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("checkConnection") - return checkConnection(c, l) - }, - Before: checkArgs, - }, - { - Name: "remote-status", - Usage: "Ask for the statuses of remote nodes indicated by " + - "`ADDRESS1 ADDRESS2 ADDRESS3...`, including the network " + - "visibility over the rest of the addresses given.", - Flags: toArray(controlFlag, jsonFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("remoteStatusCmd") - return remoteStatusCmd(c, l) - }, - }, - { - Name: "ping", - Usage: "Pings the daemon checking its state\n", - Flags: toArray(controlFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("pingpongCmd") - return pingpongCmd(c, l) - }, - }, { Name: "list-schemes", Usage: "List all scheme ids available to use\n", - Flags: toArray(controlFlag), Action: func(c *cli.Context) error { l := log.New(nil, logLevel(c), logJSON(c)). Named("schemesCmd") return schemesCmd(c, l) }, }, - { - Name: "status", - Usage: "Get the status of many modules of running the daemon\n", - Flags: toArray(controlFlag, jsonFlag, beaconIDFlag, allBeaconsFlag, listIdsFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("statusCmd") - return statusCmd(c, l) - }, - }, - { - Name: "migrate", - Usage: "Migrate folder structure to support multi-beacon drand. You DO NOT have to run it while drand is running.\n", - Flags: toArray(folderFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("migrateCmd") - return migrateCmd(c, l) - }, - Before: checkArgs, - }, - { - Name: "reset", - Usage: "Resets the local distributed information (share, group file and random beacons). It KEEPS the private/public key pair.", - Flags: toArray(folderFlag, controlFlag, beaconIDFlag, allBeaconsFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("resetCmd") - return resetCmd(c, l) - }, - Before: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("resetCmd") - return checkMigration(c, l) - }, - }, - { - Name: "del-beacon", - Usage: "Delete all beacons from the given `ROUND` number until the head of the chain. " + - " You MUST restart the daemon after that command.", - Flags: toArray(folderFlag, beaconIDFlag, allBeaconsFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("deleteBeaconCmd") - return deleteBeaconCmd(c, l) - }, - Before: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("deleteBeaconCmd") - return checkMigration(c, l) - }, - }, - { - Name: "self-sign", - Usage: "Signs the public identity of this node. Needed for backward compatibility with previous versions.", - Flags: toArray(folderFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("selfSignCmd") - return selfSign(c, l) - }, - Before: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("selfSignCmd") - return checkMigration(c, l) - }, - }, - { - Name: "backup", - Usage: "backs up the primary drand database to a secondary location.", - Flags: toArray(backupOutFlag, controlFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("backupDBCmd") - return backupDBCmd(c, l) - }, - }, - }, - }, - { - Name: "show", - Usage: "local information retrieval about the node's cryptographic " + - "material. Show prints the information about the collective " + - "public key (drand.cokey), the group details (group.toml)," + - "the long-term public key " + - "(drand.public), or the private key share (drand.share), " + - "respectively.\n", - Flags: toArray(folderFlag, controlFlag), - Subcommands: []*cli.Command{ - { - Name: "group", - Usage: "shows the current group.toml used. The group.toml " + - "may contain the distributed public key if the DKG has been " + - "ran already.\n", - Flags: toArray(outFlag, controlFlag, hashOnly, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("showGroupCmd") - return showGroupCmd(c, l) - }, - }, - { - Name: "chain-info", - Usage: "shows the chain information this node is participating to", - Flags: toArray(controlFlag, hashOnly, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("showChainInfoCmd") - return showChainInfo(c, l) - }, - }, - { - Name: "public", - Usage: "shows the long-term public key of a node.\n", - Flags: toArray(controlFlag, beaconIDFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("showPublicCmd") - return showPublicCmd(c, l) - }, - }, }, }, } @@ -934,71 +392,6 @@ func groupOut(c *cli.Context, group *key.Group) error { return nil } -func checkConnection(c *cli.Context, lg log.Logger) error { - var names []string - var beaconID string - - if c.IsSet(groupFlag.Name) { - if c.IsSet(beaconIDFlag.Name) { - return fmt.Errorf("id flag is not reqired when using group flag") - } - if err := testEmptyGroup(c.String(groupFlag.Name)); err != nil { - return err - } - group := new(key.Group) - if err := key.Load(c.String(groupFlag.Name), group); err != nil { - return fmt.Errorf("loading group failed: %w", err) - } - - for _, id := range group.Nodes { - names = append(names, id.Address()) - } - beaconID = common.GetCanonicalBeaconID(group.ID) - } else if c.Args().Present() { - for _, serverAddr := range c.Args().Slice() { - _, _, err := gonet.SplitHostPort(serverAddr) - if err != nil { - return fmt.Errorf("error for address %s: %w", serverAddr, err) - } - names = append(names, serverAddr) - } - beaconID = common.GetCanonicalBeaconID(c.String(beaconIDFlag.Name)) - } else { - return fmt.Errorf("drand: check-group expects a list of identities or %s flag", groupFlag.Name) - } - - conf := contextToConfig(c, lg) - isVerbose := c.IsSet(verboseFlag.Name) - allGood := true - isIdentityCheck := c.IsSet(groupFlag.Name) || c.IsSet(beaconIDFlag.Name) - invalidIds := make([]string, 0) - - for _, address := range names { - var err error - if isIdentityCheck { - err = checkIdentityAddress(lg, conf, address, !c.Bool(insecureFlag.Name), beaconID) - } else { - err = remotePingToNode(lg, address, !c.Bool(insecureFlag.Name)) - } - - if err != nil { - if isVerbose { - fmt.Fprintf(c.App.Writer, "drand: error checking id %s: %s\n", address, err) - } else { - fmt.Fprintf(c.App.Writer, "drand: error checking id %s\n", address) - } - allGood = false - invalidIds = append(invalidIds, address) - continue - } - fmt.Fprintf(c.App.Writer, "drand: id %s answers correctly\n", address) - } - if !allGood { - return fmt.Errorf("following nodes don't answer: %s", strings.Join(invalidIds, ",")) - } - return nil -} - func checkIdentityAddress(lg log.Logger, conf *core.Config, addr string, tls bool, beaconID string) error { peer := net.CreatePeer(addr, tls) client := net.NewGrpcClientFromCertManager(lg, conf.Certs()) @@ -1033,75 +426,6 @@ func checkIdentityAddress(lg log.Logger, conf *core.Config, addr string, tls boo return nil } -// deleteBeaconCmd deletes all beacon in the database from the given round until -// 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) - if err != nil { - return fmt.Errorf("given round not valid: %d", sr) - } - - startRound := uint64(sr) - - stores, err := getDBStoresPaths(c, l) - if err != nil { - return err - } - - verbose := isVerbose(c) - - sch, err := crypto.GetSchemeFromEnv() - if err != nil { - return err - } - if sch.Name == crypto.DefaultSchemeID { - ctx = chain.SetPreviousRequiredOnContext(ctx) - } - - var er error - for beaconID, storePath := range stores { - if er != nil { - return er - } - // Using an anonymous function to not leak the defer - er = func() error { - store, err := boltdb.NewBoltStore(ctx, l, path.Join(storePath, core.DefaultDBFolder), conf.BoltOptions()) - if err != nil { - return fmt.Errorf("beacon id [%s] - invalid bolt store creation: %w", beaconID, err) - } - defer store.Close() - - lastBeacon, err := store.Last(ctx) - if err != nil { - return fmt.Errorf("beacon id [%s] - can't fetch last beacon: %w", beaconID, err) - } - if startRound > lastBeacon.Round { - 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) - } - - for round := startRound; round <= lastBeacon.Round; round++ { - err := store.Del(ctx, round) - if err != nil { - return fmt.Errorf("beacon id [%s] - error deleting round %d: %w", beaconID, round, err) - } - if verbose { - fmt.Printf("beacon id [%s] - deleted beacon round %d \n", beaconID, round) - } - } - return nil - }() - } - - return err -} - func isVerbose(c *cli.Context) bool { return c.IsSet(verboseFlag.Name) } @@ -1121,196 +445,3 @@ func logJSON(c *cli.Context) bool { func toArray(flags ...cli.Flag) []cli.Flag { return flags } - -func getGroup(c *cli.Context) (*key.Group, error) { - g := &key.Group{} - groupPath := c.Args().First() - if err := testEmptyGroup(groupPath); err != nil { - return nil, err - } - if err := key.Load(groupPath, g); err != nil { - return nil, fmt.Errorf("drand: error loading group file: %w", err) - } - return g, nil -} - -func checkArgs(c *cli.Context) error { - 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") - } - } - if c.IsSet("certs-dir") { - _, err := fs.Files(c.String("certs-dir")) - if err != nil { - return err - } - } - - return nil -} - -func contextToConfig(c *cli.Context, l log.Logger) *core.Config { - var opts []core.ConfigOption - version := common.GetAppVersion() - - if c.IsSet(pubListenFlag.Name) { - opts = append(opts, core.WithPublicListenAddress(c.String(pubListenFlag.Name))) - } - if c.IsSet(privListenFlag.Name) { - opts = append(opts, core.WithPrivateListenAddress(c.String(privListenFlag.Name))) - } - - port := c.String(controlFlag.Name) - if port != "" { - opts = append(opts, core.WithControlPort(port)) - } - if c.IsSet(folderFlag.Name) { - opts = append(opts, core.WithConfigFolder(c.String(folderFlag.Name))) - } - opts = append(opts, core.WithVersion(fmt.Sprintf("drand/%s (%s)", version, gitCommit))) - - if c.Bool(insecureFlag.Name) { - opts = append(opts, core.WithInsecure()) - } else { - certPath, keyPath := c.String("tls-cert"), c.String("tls-key") - opts = append(opts, core.WithTLS(certPath, keyPath)) - } - if c.IsSet("certs-dir") { - paths, err := fs.Files(c.String("certs-dir")) - if err != nil { - // it wouldn't reach here, as it was verified on checkArgs func before - panic(err) - } - 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)) - case chain.PostgreSQL: - opts = append(opts, core.WithDBStorageEngine(chain.PostgreSQL)) - - if c.IsSet(pgDSNFlag.Name) { - pgdsn := c.String(pgDSNFlag.Name) - opts = append(opts, core.WithPgDSN(pgdsn)) - } - case chain.MemDB: - opts = append(opts, - core.WithDBStorageEngine(chain.MemDB), - core.WithMemDBSize(c.Int(memDBSizeFlag.Name)), - ) - default: - opts = append(opts, core.WithDBStorageEngine(chain.BoltDB)) - } - - conf := core.NewConfig(l, opts...) - return conf -} - -func getNodes(c *cli.Context) ([]*key.Node, error) { - group, err := getGroup(c) - if err != nil { - return nil, err - } - var ids []*key.Node - gids := group.Nodes - if c.IsSet("nodes") { - // search nodes listed on the flag in the group - for _, addr := range strings.Split(c.String("nodes"), ",") { - for _, gid := range gids { - if gid.Addr == addr { - ids = append(ids, gid) - } - } - } - if len(ids) == 0 { - return nil, errors.New("addresses specified don't exist in group.toml") - } - } else { - // select them all in order - ids = gids - } - if len(ids) == 0 { - return nil, errors.New("no nodes specified with --nodes are in the group file") - } - return ids, nil -} - -func testEmptyGroup(filePath string) error { - file, err := os.Open(filePath) - if err != nil { - return fmt.Errorf("can't open group path: %w", err) - } - defer file.Close() - fi, err := file.Stat() - if err != nil { - return fmt.Errorf("can't open file info: %w", err) - } - if fi.Size() == 0 { - return errors.New("group file empty") - } - return nil -} - -func getBeaconID(c *cli.Context) string { - return common.GetCanonicalBeaconID(c.String(beaconIDFlag.Name)) -} - -func getDBStoresPaths(c *cli.Context, l log.Logger) (map[string]string, error) { - conf := contextToConfig(c, l) - stores := make(map[string]string) - - if c.IsSet(allBeaconsFlag.Name) { - fi, err := os.ReadDir(conf.ConfigFolderMB()) - if err != nil { - return nil, fmt.Errorf("error trying to read stores from config folder: %w", err) - } - for _, f := range fi { - if f.IsDir() { - stores[f.Name()] = path.Join(conf.ConfigFolderMB(), f.Name()) - } - } - } else { - beaconID := getBeaconID(c) - - isPresent, err := fs.Exists(path.Join(conf.ConfigFolderMB(), beaconID)) - if err != nil || !isPresent { - return nil, fmt.Errorf("beacon id [%s] - error trying to read store: %w", beaconID, err) - } - - stores[beaconID] = path.Join(conf.ConfigFolderMB(), beaconID) - } - - return stores, nil -} - -func getKeyStores(c *cli.Context, l log.Logger) (map[string]key.Store, error) { - conf := contextToConfig(c, l) - - if c.IsSet(allBeaconsFlag.Name) { - return key.NewFileStores(conf.ConfigFolderMB()) - } - - beaconID := getBeaconID(c) - - store := key.NewFileStore(conf.ConfigFolderMB(), beaconID) - stores := map[string]key.Store{beaconID: store} - - return stores, nil -} - -func deprecatedShareCommand(_ *cli.Context) error { - return errors.New("the share command has been removed! Please use `drand dkg` instead") -} diff --git a/internal/cli_test.go b/internal/cli_test.go index 2954b8d..9f0bfc6 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -21,19 +21,19 @@ import ( json "github.com/nikkolasg/hexjson" "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/internal/chain" + "github.com/drand/drand-cli/internal/chain/boltdb" + "github.com/drand/drand-cli/internal/core" + dkg2 "github.com/drand/drand-cli/internal/dkg" + "github.com/drand/drand-cli/internal/fs" + "github.com/drand/drand-cli/internal/net" + "github.com/drand/drand-cli/internal/test" + "github.com/drand/drand-cli/internal/test/testlogger" "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/key" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/chain/boltdb" - "github.com/drand/drand/internal/core" - dkg2 "github.com/drand/drand/internal/dkg" - "github.com/drand/drand/internal/fs" - "github.com/drand/drand/internal/net" - "github.com/drand/drand/internal/test" - "github.com/drand/drand/internal/test/testlogger" "github.com/drand/kyber" "github.com/drand/kyber/share" "github.com/drand/kyber/share/dkg" diff --git a/internal/control.go b/internal/control.go index 0ab9c63..5859048 100644 --- a/internal/control.go +++ b/internal/control.go @@ -1,209 +1,13 @@ package drand import ( - "context" - "errors" "fmt" - "io" - "strings" - "sync/atomic" - "time" - - "github.com/briandowns/spinner" + "github.com/drand/drand/common/log" json "github.com/nikkolasg/hexjson" "github.com/urfave/cli/v2" - - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/key" - "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/core" - "github.com/drand/drand/internal/core/migration" - "github.com/drand/drand/internal/net" - control "github.com/drand/drand/protobuf/drand" + "io" ) -type beaconIDsStatuses struct { - Beacons map[string]*control.StatusResponse `json:"beacons"` -} - -func loadCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - beaconID := getBeaconID(c) - _, err = client.LoadBeacon(beaconID) - if err != nil { - return fmt.Errorf("could not reload the beacon process [%s]: %w", beaconID, err) - } - - fmt.Fprintf(c.App.Writer, "Beacon process [%s] was loaded on drand.\n", beaconID) - return nil -} - -func remoteStatusCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - ips := c.Args().Slice() - isTLS := !c.IsSet(insecureFlag.Name) - beaconID := getBeaconID(c) - - addresses := make([]*control.Address, len(ips)) - for i := 0; i < len(ips); i++ { - addresses[i] = &control.Address{ - Address: ips[i], - Tls: isTLS, - } - } - - resp, err := client.RemoteStatus(c.Context, addresses, beaconID) - if err != nil { - return err - } - // set default value for all keys so json outputs something for all keys - defaultMap := make(map[string]*control.StatusResponse) - switch { - case len(addresses) > 0: - for _, addr := range addresses { - if resp, ok := resp[addr.GetAddress()]; !ok { - defaultMap[addr.GetAddress()] = nil - } else { - defaultMap[addr.GetAddress()] = resp - } - } - default: - defaultMap = resp - } - - if c.IsSet(jsonFlag.Name) { - str, err := json.Marshal(defaultMap) - if err != nil { - return fmt.Errorf("cannot marshal the response ... %w", err) - } - fmt.Fprintf(c.App.Writer, "%s \n", string(str)) - } else { - for addr, resp := range defaultMap { - fmt.Fprintf(c.App.Writer, "Status of beacon %s on node %s\n", beaconID, addr) - if resp == nil { - fmt.Fprintf(c.App.Writer, "\t- NO STATUS; can't connect\n") - } else { - fmt.Fprintf(c.App.Writer, "%s\n", core.StatusResponseToString(resp)) - } - } - } - return nil -} - -func pingpongCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - if err := client.Ping(); err != nil { - return fmt.Errorf("drand: can't ping the daemon ... %w", err) - } - fmt.Fprintf(c.App.Writer, "drand daemon is alive on port %s\n", controlPort(c)) - return nil -} - -func remotePingToNode(l log.Logger, addr string, tls bool) error { - peer := net.CreatePeer(addr, tls) - client := net.NewGrpcClient(l) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - _, err := client.Home(ctx, peer, &control.HomeRequest{}) - if err != nil { - return err - } - - return nil -} - -//nolint:gocyclo -func statusCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - listIds := c.IsSet(listIdsFlag.Name) - allIds := c.IsSet(allBeaconsFlag.Name) - beaconID := c.IsSet(beaconIDFlag.Name) - - if beaconID && (allIds || listIds) { - return fmt.Errorf("drand: can't use --%s with --%s or --%s flags at the same time", - beaconIDFlag.Name, allBeaconsFlag.Name, listIdsFlag.Name) - } - - beaconIDsList := &control.ListBeaconIDsResponse{} - if allIds || listIds { - beaconIDsList, err = client.ListBeaconIDs() - if err != nil { - return fmt.Errorf("drand: can't get the list of running beacon ids on the daemon ... %w", err) - } - } else { - beaconIDsList.Ids = append(beaconIDsList.Ids, getBeaconID(c)) - } - - if listIds { - if c.IsSet(jsonFlag.Name) { - str, err := json.Marshal(beaconIDsList) - if err != nil { - return fmt.Errorf("cannot marshal the response ... %w", err) - } - fmt.Fprintf(c.App.Writer, "%s \n", string(str)) - return nil - } - - fmt.Fprintf(c.App.Writer, "running beacon ids on the node: [%s]\n", strings.Join(beaconIDsList.Ids, ", ")) - return nil - } - - statuses := beaconIDsStatuses{Beacons: make(map[string]*control.StatusResponse)} - for _, id := range beaconIDsList.Ids { - resp, err := client.Status(id) - if err != nil { - return fmt.Errorf("drand: can't get the status of the network with id [%s]... %w", id, err) - } - - if c.IsSet(jsonFlag.Name) { - statuses.Beacons[id] = resp - continue - } - - fmt.Fprintf(c.App.Writer, "the status of network with id [%s] is: \n", id) - fmt.Fprintf(c.App.Writer, "%s \n", core.StatusResponseToString(resp)) - } - - if c.IsSet(jsonFlag.Name) { - str, err := json.Marshal(statuses) - if err != nil { - return fmt.Errorf("cannot marshal the response ... %w", err) - } - fmt.Fprintf(c.App.Writer, "%s \n", string(str)) - } - - return nil -} - -func migrateCmd(c *cli.Context, l log.Logger) error { - conf := contextToConfig(c, l) - - if err := migration.MigrateSBFolderStructure(conf.ConfigFolder()); err != nil { - return fmt.Errorf("cannot migrate folder structure, please try again. err: %w", err) - } - - fmt.Fprintf(c.App.Writer, "folder structure is now ready to support multi-beacon drand\n") - return nil -} - func schemesCmd(c *cli.Context, l log.Logger) error { client, err := controlClient(c, l) if err != nil { @@ -225,94 +29,6 @@ func schemesCmd(c *cli.Context, l log.Logger) error { return nil } -func showGroupCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - beaconID := getBeaconID(c) - r, err := client.GroupFile(beaconID) - if err != nil { - return fmt.Errorf("fetching group file error: %w", err) - } - - group, err := key.GroupFromProto(r, nil) - if err != nil { - return err - } - - return groupOut(c, group) -} - -func showChainInfo(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - beaconID := getBeaconID(c) - resp, err := client.ChainInfo(beaconID) - if err != nil { - return fmt.Errorf("could not request chain info: %w", err) - } - - ci, err := chain.InfoFromProto(resp) - if err != nil { - return fmt.Errorf("could not get correct chain info: %w", err) - } - - return printChainInfo(c, ci) -} - -func showPublicCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - beaconID := getBeaconID(c) - resp, err := client.PublicKey(beaconID) - if err != nil { - return fmt.Errorf("drand: could not request drand.public: %w", err) - } - - return printJSON(c.App.Writer, resp) -} - -func backupDBCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - outDir := c.String(backupOutFlag.Name) - beaconID := getBeaconID(c) - err = client.BackupDB(outDir, beaconID) - if err != nil { - return fmt.Errorf("could not back up: %w", err) - } - - return nil -} - -func controlPort(c *cli.Context) string { - port := c.String(controlFlag.Name) - if port == "" { - port = core.DefaultControlPort - } - return port -} - -func controlClient(c *cli.Context, l log.Logger) (*net.ControlClient, error) { - port := controlPort(c) - client, err := net.NewControlClient(l, port) - if err != nil { - return nil, fmt.Errorf("can't instantiate control client: %w", err) - } - return client, nil -} - func printJSON(w io.Writer, j interface{}) error { buff, err := json.MarshalIndent(j, "", " ") if err != nil { @@ -321,215 +37,3 @@ func printJSON(w io.Writer, j interface{}) error { fmt.Fprintln(w, string(buff)) return nil } - -func selfSign(c *cli.Context, l log.Logger) error { - conf := contextToConfig(c, l) - - beaconID := getBeaconID(c) - - fs := key.NewFileStore(conf.ConfigFolderMB(), beaconID) - pair, err := fs.LoadKeyPair(nil) - - if err != nil { - return fmt.Errorf("beacon id [%s] - loading private/public: %w", beaconID, err) - } - if pair.Public.ValidSignature() == nil { - fmt.Fprintf(c.App.Writer, "beacon id [%s] - public identity already self signed.\n", beaconID) - return nil - } - - if err := pair.SelfSign(); err != nil { - return fmt.Errorf("failed to self-sign keypair for beacon id [%s]: %w", beaconID, err) - } - if err := fs.SaveKeyPair(pair); err != nil { - return fmt.Errorf("beacon id [%s] - saving identity: %w", beaconID, err) - } - - fmt.Fprintf(c.App.Writer, "beacon id [%s] - Public identity self signed for scheme %s", beaconID, pair.Scheme().Name) - fmt.Fprintln(c.App.Writer, printJSON(c.App.Writer, pair.Public.TOML())) - return nil -} - -const refreshRate = 500 * time.Millisecond - -//nolint:funlen -func checkCmd(c *cli.Context, l log.Logger) error { - defer l.Infow("Finished sync") - - ctrlClient, err := controlClient(c, l) - if err != nil { - return fmt.Errorf("unable to create control client: %w", err) - } - - addrs := strings.Split(c.String(syncNodeFlag.Name), ",") - - channel, errCh, err := ctrlClient.StartCheckChain( - c.Context, - c.String(hashInfoReq.Name), - addrs, - !c.Bool(insecureFlag.Name), - uint64(c.Int(upToFlag.Name)), - c.String(beaconIDFlag.Name)) - - if err != nil { - l.Errorw("Error checking chain", "err", err) - return fmt.Errorf("error asking to check chain up to %d: %w", c.Int(upToFlag.Name), err) - } - - var current uint64 - target := uint64(c.Int(upToFlag.Name)) - s := spinner.New(spinner.CharSets[9], refreshRate) - s.PreUpdate = func(spin *spinner.Spinner) { - curr := atomic.LoadUint64(¤t) - spin.Suffix = fmt.Sprintf(" synced round up to %d "+ - "\t- current target %d"+ - "\t--> %.3f %% - "+ - "Waiting on new rounds...", curr, target, 100*float64(curr)/float64(target)) - } - s.Start() - defer s.Stop() - - // The following could be much simpler if we don't want to be nice on the user and display comprehensive logs - // on the client side. - isCorrecting, success := false, false - for { - select { - case progress, ok := <-channel: - if !ok { - // let the spinner time to refresh - time.Sleep(refreshRate) - if success { - // we need an empty line to not clash with the spinner - fmt.Println() - l.Infow("Finished correcting faulty beacons, " + - "we recommend running the same command a second time to confirm all beacons are now valid") - } - return nil - } - // if we received at least one progress update after switching to correcting - success = isCorrecting - if progress.Current == 0 { - // let the spinner time to refresh - time.Sleep(refreshRate) - // we need an empty line to not clash with the spinner - fmt.Println() - l.Infow("Finished checking chain validity") - if progress.Target > 0 { - l.Warnw("Faulty beacon found!", "amount", progress.Target) - isCorrecting = true - } else { - l.Warnw("No faulty beacon found!") - } - } - atomic.StoreUint64(¤t, progress.Current) - atomic.StoreUint64(&target, progress.Target) - case err, ok := <-errCh: - if !ok { - l.Infow("Error channel was closed") - return nil - } - // note that grpc's "error reading from server: EOF" won't trigger this so we really only catch the case - // where the server gracefully closed the connection. - if errors.Is(err, io.EOF) { - // let the spinner time to refresh - time.Sleep(refreshRate) - // make sure to exhaust our progress channel - progress, ok := <-channel - if ok { - if atomic.LoadUint64(&target) > progress.Target { - // we need an empty line to not clash with the spinner - fmt.Println() - l.Infow("Finished checking chain validity") - l.Warnw("Faulty beacon found!", "amount", progress.Target) - } else { - atomic.StoreUint64(¤t, progress.Current) - // let the spinner time to refresh again - time.Sleep(refreshRate) - // we need an empty line to not clash with the spinner - fmt.Println() - } - } - - if success { - // we need an empty line to not clash with the spinner - fmt.Println() - l.Infow("Finished correcting faulty beacons, " + - "we recommend running the same command a second time to confirm all beacons are now valid") - } - - return nil - } - - l.Errorw("received an error", "err", err) - return fmt.Errorf("errror when checking the chain: %w", err) - } - } -} - -func syncCmd(c *cli.Context, l log.Logger) error { - if c.Bool(followFlag.Name) { - return followSync(c, l) - } - - return checkCmd(c, l) -} - -func followSync(c *cli.Context, l log.Logger) error { - ctrlClient, err := controlClient(c, l) - if err != nil { - return fmt.Errorf("unable to create control client: %w", err) - } - defer ctrlClient.Close() - - addrs := strings.Split(c.String(syncNodeFlag.Name), ",") - channel, errCh, err := ctrlClient.StartFollowChain( - c.Context, - c.String(hashInfoReq.Name), - addrs, - !c.Bool(insecureFlag.Name), - uint64(c.Int(upToFlag.Name)), - getBeaconID(c)) - - if err != nil { - return fmt.Errorf("error asking to follow chain: %w", err) - } - - var current uint64 - var target uint64 - - last := time.Now().Unix() - - s := spinner.New(spinner.CharSets[9], refreshRate) - s.PreUpdate = func(spin *spinner.Spinner) { - curr := atomic.LoadUint64(¤t) - tar := atomic.LoadUint64(&target) - dur := time.Now().Unix() - atomic.LoadInt64(&last) - - spin.Suffix = fmt.Sprintf(" synced round up to %d "+ - "- current target %d"+ - "\t--> %.3f %% - "+ - "Last update received %3ds ago. Waiting on new rounds...", curr, tar, 100*float64(curr)/float64(tar), dur) - } - - s.FinalMSG = "\nSync stopped\n" - - s.Start() - defer s.Stop() - for { - select { - case progress := <-channel: - atomic.StoreUint64(¤t, progress.Current) - atomic.StoreUint64(&target, progress.Target) - atomic.StoreInt64(&last, time.Now().Unix()) - case err := <-errCh: - if errors.Is(err, io.EOF) { - // we need a new line because of the spinner - fmt.Println() - l.Infow("Finished following beacon chain", "reached", current, - "server closed stream with", err) - return nil - } - return fmt.Errorf("errror on following the chain: %w", err) - } - } -} diff --git a/internal/daemon.go b/internal/daemon.go deleted file mode 100644 index de43651..0000000 --- a/internal/daemon.go +++ /dev/null @@ -1,80 +0,0 @@ -package drand - -import ( - "fmt" - - "github.com/urfave/cli/v2" - "go.opentelemetry.io/otel/attribute" - - "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/core" - "github.com/drand/drand/internal/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(ctx, conf) - if err != nil { - 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(ctx, c.String(metricsFlag.Name), singleBeacon, c.String(beaconIDFlag.Name)) - if err != nil { - err = fmt.Errorf("couldn't load existing beacons: %w", err) - span.RecordError(err) - span.End() - return err - } - - span.End() - <-drandDaemon.WaitExit() - return nil -} - -func stopDaemon(c *cli.Context, lg log.Logger) error { - ctrlClient, err := controlClient(c, lg) - if err != nil { - return err - } - defer ctrlClient.Close() - - isBeaconIDSet := c.IsSet(beaconIDFlag.Name) - if isBeaconIDSet { - beaconID := getBeaconID(c) - _, err = ctrlClient.Shutdown(beaconID) - - if err != nil { - return fmt.Errorf("error stopping beacon process [%s]: %w", beaconID, err) - } - fmt.Fprintf(c.App.Writer, "beacon process [%s] stopped correctly. Bye.\n", beaconID) - } else { - _, err = ctrlClient.Shutdown("") - - if err != nil { - return fmt.Errorf("error stopping drand daemon: %w", err) - } - fmt.Fprintf(c.App.Writer, "drand daemon stopped correctly. Bye.\n") - } - - return nil -} diff --git a/internal/dkg_cli.go b/internal/dkg_cli.go deleted file mode 100644 index c2d8ec3..0000000 --- a/internal/dkg_cli.go +++ /dev/null @@ -1,789 +0,0 @@ -package drand - -import ( - "context" - "encoding/hex" - "errors" - "fmt" - "os" - "strconv" - "strings" - "time" - - "github.com/BurntSushi/toml" - "github.com/jedib0t/go-pretty/v6/table" - "github.com/urfave/cli/v2" - "google.golang.org/protobuf/types/known/timestamppb" - - "github.com/drand/drand/common" - "github.com/drand/drand/common/key" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/chain" - "github.com/drand/drand/internal/core" - "github.com/drand/drand/internal/dkg" - "github.com/drand/drand/internal/net" - "github.com/drand/drand/internal/util" - common2 "github.com/drand/drand/protobuf/common" - "github.com/drand/drand/protobuf/drand" -) - -var dkgCommand = &cli.Command{ - Name: "dkg", - Usage: "Commands for interacting with the DKG", - Subcommands: []*cli.Command{ - { - Name: "propose", - Flags: toArray( - beaconIDFlag, - controlFlag, - schemeFlag, - periodFlag, - thresholdFlag, - catchupPeriodFlag, - proposalFlag, - secretFlag, - dkgTimeoutFlag, - transitionTimeFlag, - ), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("dkgPropose") - return makeProposal(c, l) - }, - }, - { - Name: "join", - Flags: toArray( - beaconIDFlag, - controlFlag, - secretFlag, - groupFlag, - ), - Action: joinNetwork, - }, - { - Name: "execute", - Flags: toArray( - beaconIDFlag, - controlFlag, - ), - Action: executeDKG, - }, - { - Name: "accept", - Flags: toArray( - beaconIDFlag, - controlFlag, - ), - Action: acceptDKG, - }, - { - Name: "reject", - Flags: toArray( - beaconIDFlag, - controlFlag, - ), - Action: rejectDKG, - }, - { - Name: "abort", - Flags: toArray( - beaconIDFlag, - controlFlag, - ), - Action: abortDKG, - }, - { - Name: "status", - Flags: toArray( - beaconIDFlag, - controlFlag, - formatFlag, - ), - Action: viewStatus, - }, - { - Name: "generate-proposal", - Flags: toArray( - joinerFlag, - remainerFlag, - proposalOutputFlag, - beaconIDFlag, - controlFlag, - leaverFlag, - ), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("dkgGenerateProposal") - return generateProposalCmd(c, l) - }, - }, - }, -} - -var joinerFlag = &cli.StringSliceFlag{ - Name: "joiner", - Usage: "the address of a joiner you wish to add to a DKG proposal. You can pass it multiple times. " + - "To use TLS, prefix their address with 'https://'", -} - -var remainerFlag = &cli.StringSliceFlag{ - Name: "remainer", - Usage: "the address of a remainer you wish to add to a DKG proposal. You can pass it multiple times. " + - "To use TLS, prefix their address with 'https://'", -} - -var leaverFlag = &cli.StringSliceFlag{ - Name: "leaver", - Usage: "the address of a leaver you wish to add to the DKG proposal. You can pass it multiple times. " + - "To use TLS, prefix their address with 'https://'", -} - -var proposalOutputFlag = &cli.StringFlag{ - Name: "out", - Usage: "the location you wish to save the proposal file to", -} - -var formatFlag = &cli.StringFlag{ - Name: "format", - Usage: "Set the format of the status output. Valid options are: pretty, csv", - Value: "pretty", - EnvVars: []string{"DRAND_STATUS_FORMAT"}, -} - -var transitionTimeFlag = &cli.StringFlag{ - Name: "transition-time", - Usage: "The duration from now until which keys generated during the next DKG should be used. It will be modified to the nearest round.", -} - -var dkgTimeoutFlag = &cli.StringFlag{ - Name: "timeout", - Usage: "The duration from now in which DKG participants should abort the DKG if it has not completed.", - Value: "24h", -} - -func makeProposal(c *cli.Context, l log.Logger) error { - controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) - client, err := net.NewDKGControlClient(l, controlPort) - if err != nil { - return err - } - - beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) - - if isInitialProposal(c) { - proposal, err := parseInitialProposal(c) - if err != nil { - return err - } - - _, err = client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Initial{Initial: proposal}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - if err != nil { - return err - } - } else { - proposal, err := parseProposal(c, l) - if err != nil { - return err - } - - _, err = client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Resharing{Resharing: proposal}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - if err != nil { - return fmt.Errorf("proposal was unsuccessful - you may need to issue an abort command. Error: %w", err) - } - } - - fmt.Println("Proposal made successfully!") - return nil -} - -func isInitialProposal(c *cli.Context) bool { - return c.IsSet(schemeFlag.Name) -} - -func withDefault(first, second string) string { - if first == "" { - return second - } - - return first -} - -func parseInitialProposal(c *cli.Context) (*drand.FirstProposalOptions, error) { - requiredFlags := []*cli.StringFlag{proposalFlag, periodFlag, schemeFlag, catchupPeriodFlag, transitionTimeFlag} - - for _, flag := range requiredFlags { - if !c.IsSet(flag.Name) { - return nil, fmt.Errorf("%s flag is required for initial proposals", flag.Name) - } - } - - // this is IntFlag and not StringFlag so must be checked separately - if !c.IsSet(thresholdFlag.Name) { - return nil, fmt.Errorf("%s flag is required for initial proposals", thresholdFlag.Name) - } - - proposalFile, err := ParseProposalFile(c.String(proposalFlag.Name)) - if err != nil { - return nil, err - } - - err = validateInitialProposal(proposalFile) - if err != nil { - return nil, err - } - - period := c.Duration(periodFlag.Name) - timeout := time.Now().Add(c.Duration(dkgTimeoutFlag.Name)) - - genesisTime := time.Now().Add(c.Duration(transitionTimeFlag.Name)) - - return &drand.FirstProposalOptions{ - Timeout: timestamppb.New(timeout), - Threshold: uint32(c.Int(thresholdFlag.Name)), - PeriodSeconds: uint32(period.Seconds()), - Scheme: c.String(schemeFlag.Name), - CatchupPeriodSeconds: uint32(c.Duration(catchupPeriodFlag.Name).Seconds()), - GenesisTime: timestamppb.New(genesisTime), - Joining: proposalFile.Joining, - }, nil -} - -func validateInitialProposal(proposalFile *ProposalFile) error { - if len(proposalFile.Leaving) != 0 || len(proposalFile.Remaining) != 0 { - return fmt.Errorf("your proposal file must not have `Leaving` or `Remaining` for an initial DKG proposal") - } - - if len(proposalFile.Joining) == 0 { - return fmt.Errorf("your proposal file must have `Joining`") - } - - return nil -} - -func parseProposal(c *cli.Context, l log.Logger) (*drand.ProposalOptions, error) { - beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) - bannedFlags := []*cli.StringFlag{periodFlag, schemeFlag} - for _, flag := range bannedFlags { - if c.IsSet(flag.Name) { - return nil, fmt.Errorf("%s flag can only be set for initial proposals", flag.Name) - } - } - - if !c.IsSet(proposalFlag.Name) { - return nil, fmt.Errorf("%s flag is required ", proposalFlag.Name) - } - - if !c.IsSet(thresholdFlag.Name) { - return nil, fmt.Errorf("%s flag is required", thresholdFlag.Name) - } - - // parse a proposal file from the path specified - proposalFilePath := c.String(proposalFlag.Name) - proposalFile, err := ParseProposalFile(proposalFilePath) - if err != nil { - return nil, err - } - - if len(proposalFile.Remaining) == 0 { - return nil, fmt.Errorf("you must provider remainers for a proposal") - } - - var timeout time.Time - if c.IsSet(dkgTimeoutFlag.Name) { - timeout = time.Now().Add(c.Duration(dkgTimeoutFlag.Name)) - } else { - timeout = time.Now().Add(core.DefaultDKGTimeout) - } - - // figure out the round closest to the transition duration provided - var transitionTime time.Time - if c.IsSet(transitionTimeFlag.Name) { - transitionTime = time.Now().Add(c.Duration(transitionTimeFlag.Name)) - } else { - transitionTime = time.Now().Add(1 * time.Minute) - } - - // first we get the chainInfo for the beacon - var ctrlPort string - if c.IsSet(controlFlag.Name) { - ctrlPort = c.String(controlFlag.Name) - } else { - ctrlPort = core.DefaultControlPort - } - - ctrlClient, err := net.NewControlClient(l, ctrlPort) - if err != nil { - return nil, err - } - info, err := ctrlClient.ChainInfo(beaconID) - if err != nil { - return nil, err - } - - // then we use it to work out the real transition time - transitionRound := chain.CurrentRound(transitionTime.Unix(), time.Duration(info.Period)*time.Second, info.GenesisTime) - actualTransitionTime := chain.TimeOfRound(time.Duration(info.Period)*time.Second, info.GenesisTime, transitionRound) - - return &drand.ProposalOptions{ - Timeout: timestamppb.New(timeout), - TransitionTime: timestamppb.New(time.Unix(actualTransitionTime, 0)), - Threshold: uint32(c.Int(thresholdFlag.Name)), - CatchupPeriodSeconds: uint32(c.Duration(catchupPeriodFlag.Name).Seconds()), - Joining: proposalFile.Joining, - Leaving: proposalFile.Leaving, - Remaining: proposalFile.Remaining, - }, nil -} - -func joinNetwork(c *cli.Context) error { - l := log.FromContextOrDefault(c.Context) - beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) - controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) - - var groupFile []byte - if c.IsSet(groupFlag.Name) { - fileContents, err := os.ReadFile(c.String(groupFlag.Name)) - if err != nil { - return err - } - groupFile = fileContents - } - - client, err := net.NewDKGControlClient(l, controlPort) - if err != nil { - return err - } - _, err = client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Join{Join: &drand.JoinOptions{ - GroupFile: groupFile, - }}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - - if err == nil { - fmt.Println("Joined the DKG successfully!") - } - return err -} - -func executeDKG(c *cli.Context) error { - err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { - _, err := client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Execute{Execute: &drand.ExecutionOptions{}}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - return err - }) - - if err == nil { - fmt.Println("DKG execution started successfully!") - } - return err -} - -func acceptDKG(c *cli.Context) error { - err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { - _, err := client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Accept{Accept: &drand.AcceptOptions{}}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - return err - }) - - if err == nil { - fmt.Println("DKG accepted successfully!") - } - return err -} - -func rejectDKG(c *cli.Context) error { - err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { - _, err := client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Reject{Reject: &drand.RejectOptions{}}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - return err - }) - - if err == nil { - fmt.Println("DKG rejected successfully!") - } - - return err -} - -func abortDKG(c *cli.Context) error { - err := runSimpleAction(c, func(beaconID string, client drand.DKGControlClient) error { - _, err := client.Command(c.Context, &drand.DKGCommand{ - Command: &drand.DKGCommand_Abort{Abort: &drand.AbortOptions{}}, - Metadata: &drand.CommandMetadata{ - BeaconID: beaconID, - }, - }) - return err - }) - if err == nil { - fmt.Println("DKG aborted successfully!") - } - return err -} - -func runSimpleAction(c *cli.Context, action func(beaconID string, client drand.DKGControlClient) error) error { - l := log.FromContextOrDefault(c.Context) - beaconID := withDefault(c.String(beaconIDFlag.Name), common.DefaultBeaconID) - controlPort := withDefault(c.String(controlFlag.Name), core.DefaultControlPort) - - client, err := net.NewDKGControlClient(l, controlPort) - if err != nil { - return err - } - return action(beaconID, client) -} - -func viewStatus(c *cli.Context) error { - l := log.FromContextOrDefault(c.Context) - var beaconID string - if c.IsSet(beaconIDFlag.Name) { - beaconID = c.String(beaconIDFlag.Name) - } else { - beaconID = common.DefaultBeaconID - } - - var controlPort string - if c.IsSet(controlFlag.Name) { - controlPort = c.String(controlFlag.Name) - } else { - controlPort = core.DefaultControlPort - } - - client, err := net.NewDKGControlClient(l, controlPort) - if err != nil { - return err - } - - status, err := client.DKGStatus(context.Background(), &drand.DKGStatusRequest{BeaconID: beaconID}) - if err != nil { - return err - } - - if !c.IsSet(formatFlag.Name) || c.String(formatFlag.Name) == "pretty" { - prettyPrint(status) - } else if c.String(formatFlag.Name) == "csv" { - csvPrint(c, "<>", status.Current) - csvPrint(c, "<>", status.Complete) - } else { - return errors.New("invalid format flag") - } - return nil -} - -func csvPrint(c *cli.Context, tag string, entry *drand.DKGEntry) { - out := c.App.Writer - _, _ = fmt.Fprintf(out, "%s", tag) - if entry == nil { - _, _ = fmt.Fprintln(out, "nil") - return - } - - _, err := fmt.Fprintf( - c.App.Writer, - "BeaconID:%s,State:%s,Epoch:%d,Threshold:%d,Timeout:%s,GenesisTime:%s,TransitionTime:%s,GenesisSeed:%s,Leader:%s", - entry.BeaconID, - dkg.Status(entry.State).String(), - entry.Epoch, - entry.Threshold, - entry.Timeout.AsTime().String(), - entry.GenesisTime.AsTime().String(), - entry.TransitionTime.AsTime().String(), - hex.EncodeToString(entry.GenesisSeed), - entry.Leader.Address, - ) - if err != nil { - _, _ = fmt.Fprintln(out, "error") - } -} - -type printModel struct { - Status string - BeaconID string - Epoch string - Threshold string - Timeout string - GenesisTime string - TransitionTime string - GenesisSeed string - Leader string - Joining string - Remaining string - Leaving string - Accepted string - Rejected string - FinalGroup string -} - -func convert(entry *drand.DKGEntry) printModel { - formatAddresses := func(arr []*drand.Participant) string { - if len(arr) == 0 { - return "[]" - } - if len(arr) == 1 { - return fmt.Sprintf("[%s]", arr[0].Address) - } - - b := strings.Builder{} - b.WriteString("[") - for _, a := range arr { - b.WriteString(fmt.Sprintf("\n\t%s,", a.Address)) - } - b.WriteString("\n]") - - return b.String() - } - - formatFinalGroup := func(group []string) string { - if group == nil { - return "" - } - b := strings.Builder{} - b.WriteString("[") - for _, a := range group { - b.WriteString(fmt.Sprintf("\n\t%s,", a)) - } - b.WriteString("\n]") - return b.String() - } - - return printModel{ - Status: dkg.Status(entry.State).String(), - BeaconID: entry.BeaconID, - Epoch: strconv.Itoa(int(entry.Epoch)), - Threshold: strconv.Itoa(int(entry.Threshold)), - Timeout: entry.Timeout.AsTime().Format(time.RFC3339), - GenesisTime: entry.GenesisTime.AsTime().Format(time.RFC3339), - TransitionTime: entry.TransitionTime.AsTime().Format(time.RFC3339), - GenesisSeed: hex.EncodeToString(entry.GenesisSeed), - Leader: entry.Leader.Address, - Joining: formatAddresses(entry.Joining), - Remaining: formatAddresses(entry.Remaining), - Leaving: formatAddresses(entry.Leaving), - Accepted: formatAddresses(entry.Acceptors), - Rejected: formatAddresses(entry.Rejectors), - FinalGroup: formatFinalGroup(entry.FinalGroup), - } -} - -func prettyPrint(status *drand.DKGStatusResponse) { - tw := table.NewWriter() - tw.AppendHeader(table.Row{"Field", "Current", "Finished"}) - - if dkg.Status(status.Current.State) == dkg.Fresh { - tw.AppendRow(table.Row{"State", "Fresh", "Fresh"}) - fmt.Println(tw.Render()) - return - } - - currentModel := convert(status.Current) - finishedModel := convert(status.Complete) - - tw.AppendRow(table.Row{"Status", currentModel.Status, finishedModel.Status}) - tw.AppendRow(table.Row{"Epoch", currentModel.Epoch, finishedModel.Epoch}) - tw.AppendRow(table.Row{"BeaconID", currentModel.BeaconID, finishedModel.BeaconID}) - tw.AppendRow(table.Row{"Threshold", currentModel.Threshold, finishedModel.Threshold}) - tw.AppendRow(table.Row{"Timeout", currentModel.Timeout, finishedModel.Timeout}) - tw.AppendRow(table.Row{"GenesisTime", currentModel.GenesisTime, finishedModel.GenesisTime}) - tw.AppendRow(table.Row{"TransitionTime", currentModel.TransitionTime, finishedModel.TransitionTime}) - tw.AppendRow(table.Row{"GenesisSeed", currentModel.GenesisSeed, finishedModel.GenesisSeed}) - tw.AppendRow(table.Row{"Leader", currentModel.Leader, finishedModel.Leader}) - tw.AppendRow(table.Row{"Joining", currentModel.Joining, finishedModel.Joining}) - tw.AppendRow(table.Row{"Remaining", currentModel.Remaining, finishedModel.Remaining}) - tw.AppendRow(table.Row{"Leaving", currentModel.Leaving, finishedModel.Leaving}) - tw.AppendRow(table.Row{"Accepted", currentModel.Accepted, finishedModel.Accepted}) - tw.AppendRow(table.Row{"Rejected", currentModel.Rejected, finishedModel.Rejected}) - tw.AppendRow(table.Row{"FinalGroup", currentModel.FinalGroup, finishedModel.FinalGroup}) - - fmt.Println(tw.Render()) -} - -func generateProposalCmd(c *cli.Context, l log.Logger) error { - // first we validate the flags - if !c.IsSet(joinerFlag.Name) && !c.IsSet(remainerFlag.Name) { - return errors.New("you must add joiners and/or remainers to the proposal") - } - - if !c.IsSet(proposalOutputFlag.Name) { - return errors.New("you must pass an output filepath for the proposal") - } - - var beaconID string - if c.IsSet(beaconIDFlag.Name) { - beaconID = c.String(beaconIDFlag.Name) - } else { - beaconID = common.DefaultBeaconID - } - - // then we fetch the current group file - proposalFile := ProposalFile{} - client, err := controlClient(c, l) - if err != nil { - return err - } - - freshStart := false - r, err := client.GroupFile(beaconID) - - if err != nil { - // if it's a fresh start, we'll take a different path - if errors.Is(err, core.ErrNoGroupSetup) { - freshStart = true - } else { - return err - } - } - - joiners := c.StringSlice(joinerFlag.Name) - remainers := c.StringSlice(remainerFlag.Name) - leavers := c.StringSlice(leaverFlag.Name) - - if freshStart { - if len(remainers) > 0 { - return errors.New("the network isn't running yet - cannot have remainers") - } - if len(leavers) > 0 { - return errors.New("the network isn't running yet - cannot have leavers") - } - } else { - current := make([]*drand.Participant, len(r.Nodes)) - for i, node := range r.Nodes { - address := node.Public.Address - if !util.Cont(util.Concat(remainers, leavers), address) { - return fmt.Errorf("%s is missing in the attempted proposal but exists in the current network. It should be leaving or remaining", address) - } - current[i] = util.ToParticipant(node) - } - - for _, remainer := range remainers { - matching, err := util.First(current, func(participant *drand.Participant) bool { - return participant.Address == remainer - }) - if err != nil { - return fmt.Errorf("remainer %s is missing in the current network", remainer) - } - proposalFile.Remaining = append(proposalFile.Remaining, *matching) - } - - for _, leaver := range leavers { - matching, err := util.First(current, func(participant *drand.Participant) bool { - return participant.Address == leaver - }) - if err != nil { - return fmt.Errorf("leaver %s is missing in the current network", leaver) - } - proposalFile.Leaving = append(proposalFile.Leaving, *matching) - } - } - - identityResp, err := client.PublicKey(beaconID) - if err != nil { - return err - } - sch, err := crypto.SchemeFromName(identityResp.GetSchemeName()) - if err != nil { - return key.ErrInvalidKeyScheme - } - - id, err := key.IdentityFromProto(&drand.Identity{ - Signature: identityResp.Signature, - Tls: identityResp.Tls, - Address: identityResp.Addr, - Key: identityResp.PubKey, - }, sch) - if err != nil { - return key.ErrInvalidKeyScheme - } - - if err = id.ValidSignature(); err != nil { - return key.ErrInvalidKeyScheme - } - - // we fetch the keys for all the new joiners by calling their node's API - for _, joiner := range joiners { - p, err := fetchPublicKey(beaconID, l, joiner, sch) - if err != nil { - return err - } - proposalFile.Joining = append(proposalFile.Joining, p) - } - - // finally we write the proposal toml file to the output location - filepath := c.String(proposalOutputFlag.Name) - file, err := os.Create(filepath) - if err != nil { - return err - } - - err = toml.NewEncoder(file).Encode(proposalFile.TOML()) - if err != nil { - return err - } - - fmt.Printf("Proposal created successfully at path %s", filepath) - return nil -} - -func fetchPublicKey(beaconID string, l log.Logger, address string, targetSch *crypto.Scheme) (*drand.Participant, error) { - parts := strings.Split(address, "https://") - tls := len(parts) > 1 - var peer net.Peer - if tls { - peer = net.CreatePeer(parts[1], tls) - } else { - peer = net.CreatePeer(address, tls) - } - client := net.NewGrpcClient(l) - identity, err := client.GetIdentity(context.Background(), peer, &drand.IdentityRequest{Metadata: &common2.Metadata{BeaconID: beaconID}}) - if err != nil { - return nil, fmt.Errorf("could not fetch public key for %s: %v", address, err) - } - - if identity.SchemeName != targetSch.Name { - return nil, key.ErrInvalidKeyScheme - } - - part := &drand.Participant{ - Address: identity.Address, - Tls: identity.Tls, - Key: identity.Key, - Signature: identity.Signature, - } - - id, err := key.IdentityFromProto(part, targetSch) - if err != nil { - return nil, err - } - l.Debugw("Validating signature for", id.Addr, "scheme", targetSch.Name) - if err := id.ValidSignature(); err != nil { - return nil, key.ErrInvalidKeyScheme - } - - return part, nil -} diff --git a/internal/dkg_cli_test.go b/internal/dkg_cli_test.go deleted file mode 100644 index 9cd61b8..0000000 --- a/internal/dkg_cli_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package drand - -import ( - "encoding/hex" - "testing" - "time" - - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/types/known/timestamppb" - - "github.com/drand/drand/common/key" - "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/dkg" - "github.com/drand/drand/protobuf/drand" -) - -func TestDKGPrintModelConversion(t *testing.T) { - now := time.Date(2023, 1, 1, 1, 1, 2, 0, time.UTC) - genesisSeed, err := hex.DecodeString("deadbeef") - require.NoError(t, err) - entry := drand.DKGEntry{ - BeaconID: "banana", - State: uint32(dkg.Complete), - Epoch: 3, - Threshold: 2, - Timeout: timestamppb.New(now), - GenesisTime: timestamppb.New(now.Add(1 * time.Minute)), - TransitionTime: timestamppb.New(now.Add(2 * time.Minute)), - GenesisSeed: genesisSeed, - Leader: NewParticipant("alice"), - Remaining: []*drand.Participant{NewParticipant("alice"), NewParticipant("bob"), NewParticipant("carol")}, - Joining: []*drand.Participant{NewParticipant("david")}, - Leaving: nil, - Acceptors: nil, - Rejectors: nil, - FinalGroup: []string{"alice", "bob", "carol"}, - } - printModel := convert(&entry) - - require.Equal(t, "banana", printModel.BeaconID) - require.Equal(t, "Complete", printModel.Status) - require.Equal(t, "3", printModel.Epoch) - require.Equal(t, "2", printModel.Threshold) - require.Equal(t, "2023-01-01T01:01:02Z", printModel.Timeout) - require.Equal(t, "2023-01-01T01:02:02Z", printModel.GenesisTime) - require.Equal(t, "2023-01-01T01:03:02Z", printModel.TransitionTime) - require.Equal(t, "deadbeef", printModel.GenesisSeed) - require.Equal(t, "alice", printModel.Leader) - require.Equal(t, "[\n\talice,\n\tbob,\n\tcarol,\n]", printModel.Remaining) - require.Equal(t, `[david]`, printModel.Joining) - require.Equal(t, "[]", printModel.Leaving) - require.Equal(t, "[]", printModel.Accepted) - require.Equal(t, "[]", printModel.Rejected) - require.Equal(t, "[\n\talice,\n\tbob,\n\tcarol,\n]", printModel.FinalGroup) -} - -func NewParticipant(name string) *drand.Participant { - sch, _ := crypto.GetSchemeFromEnv() - k, _ := key.NewKeyPair(name, sch) - pk, _ := k.Public.Key.MarshalBinary() - return &drand.Participant{ - Address: name, - Tls: false, - Key: pk, - } -} diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index edd19f5..4e774ee 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -15,13 +15,13 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" + "github.com/drand/drand-cli/internal/test/mock" + "github.com/drand/drand-cli/internal/test/testlogger" client2 "github.com/drand/drand/client" httpmock "github.com/drand/drand/client/test/http/mock" commonutils "github.com/drand/drand/common" "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/internal/test/mock" - "github.com/drand/drand/internal/test/testlogger" ) var ( diff --git a/internal/proposal_file_test.go b/internal/proposal_file_test.go index 9cd5422..9f8c3be 100644 --- a/internal/proposal_file_test.go +++ b/internal/proposal_file_test.go @@ -7,8 +7,8 @@ import ( "github.com/BurntSushi/toml" + "github.com/drand/drand-cli/internal/net" "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/net" ) func generateJoiningProposal(l log.Logger, beaconID string, joining []string) (string, error) { @@ -33,7 +33,6 @@ func generateProposal(l log.Logger, beaconID string, joining, remaining, leaving } participants = append(participants, &TomlParticipant{ Address: res.Addr, - TLS: res.Tls, Key: hex.EncodeToString(res.PubKey), Signature: hex.EncodeToString(res.Signature), }) diff --git a/internal/public.go b/internal/public.go deleted file mode 100644 index 6747147..0000000 --- a/internal/public.go +++ /dev/null @@ -1,116 +0,0 @@ -package drand - -import ( - "encoding/hex" - "errors" - "fmt" - gonet "net" - "os" - - "github.com/urfave/cli/v2" - - "github.com/drand/drand/client/grpc" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/internal/core" - "github.com/drand/drand/internal/net" -) - -func getPublicRandomness(c *cli.Context, lg log.Logger) error { - if !c.Args().Present() { - return errors.New("get public command takes a group file as argument") - } - - certPath := "" - if c.IsSet(tlsCertFlag.Name) { - certPath = c.String(tlsCertFlag.Name) - } - - ids, err := getNodes(c) - if err != nil { - return err - } - - group, err := getGroup(c) - if err != nil { - return err - } - if group.PublicKey == nil { - return errors.New("drand: group file must contain the distributed public key") - } - - info := chain.NewChainInfo(lg, group) - - var resp client.Result - var foundCorrect bool - for _, id := range ids { - grpcClient, err := grpc.New(lg, id.Addr, certPath, !id.TLS, info.Hash()) - if err != nil { - fmt.Fprintf(os.Stderr, "drand: could not connect to %s: %s\n", id.Addr, err) - break - } - - resp, err = grpcClient.Get(c.Context, uint64(c.Int(roundFlag.Name))) - - if err == nil { - foundCorrect = true - if c.Bool(verboseFlag.Name) { - fmt.Fprintf(c.App.Writer, "drand: public randomness retrieved from %s\n", id.Addr) - } - break - } - fmt.Fprintf(os.Stderr, "drand: could not get public randomness from %s: %s\n", id.Addr, err) - } - if !foundCorrect { - return errors.New("drand: could not verify randomness") - } - - return printJSON(c.App.Writer, resp) -} - -func getChainInfo(c *cli.Context, lg log.Logger) error { - ctx := c.Context - var err error - chainHash := make([]byte, 0) - if c.IsSet(hashInfoNoReq.Name) { - if chainHash, err = hex.DecodeString(c.String(hashInfoNoReq.Name)); err != nil { - return fmt.Errorf("invalid chain hash given: %w", err) - } - } - - grpcClient := core.NewGrpcClient(lg, chainHash) - if c.IsSet(tlsCertFlag.Name) { - defaultManager := net.NewCertManager(lg) - certPath := c.String(tlsCertFlag.Name) - if err := defaultManager.Add(certPath); err != nil { - return err - } - grpcClient = core.NewGrpcClientFromCert(lg, chainHash, defaultManager) - } - var ci *chain.Info - for _, addr := range c.Args().Slice() { - _, _, err := gonet.SplitHostPort(addr) - if err != nil { - return fmt.Errorf("invalid address given: %w", err) - } - ci, err = grpcClient.ChainInfo(ctx, net.CreatePeer(addr, !c.Bool("tls-disable"))) - if err == nil { - break - } - fmt.Fprintf(os.Stderr, "drand: error fetching distributed key from %s : %s\n", - addr, err) - } - if ci == nil { - return errors.New("drand: can't retrieve dist. key from any nodes") - } - return printChainInfo(c, ci) -} - -func printChainInfo(c *cli.Context, ci *chain.Info) error { - if c.Bool(hashOnly.Name) { - fmt.Fprintf(c.App.Writer, "%s\n", hex.EncodeToString(ci.Hash())) - return nil - } - return printJSON(c.App.Writer, ci.ToProto(nil)) -} diff --git a/main.go b/main.go index f23f558..d04cbfb 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/drand/drand/internal/drand-cli" + "github.com/drand/drand-cli/internal/drand" ) func main() { From bd1664d1c67393bdb423994829c7ce580e7d6aca Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 31 Aug 2023 18:12:03 +0200 Subject: [PATCH 03/28] adding go.mod --- go.mod | 179 ++++++ go.sum | 1794 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1973 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..675992d --- /dev/null +++ b/go.mod @@ -0,0 +1,179 @@ +module github.com/drand/drand-cli + +go 1.20 + +replace github.com/drand/drand => ../drand + +require ( + github.com/BurntSushi/toml v1.3.2 + github.com/drand/drand v0.0.0-00010101000000-000000000000 + github.com/drand/kyber v1.2.0 + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 + github.com/hashicorp/go-multierror v1.1.1 + github.com/hashicorp/golang-lru v1.0.2 + github.com/ipfs/go-ds-badger2 v0.1.3 + github.com/jonboulle/clockwork v0.4.0 + github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 + github.com/libp2p/go-libp2p v0.30.0 + github.com/libp2p/go-libp2p-pubsub v0.9.3 + github.com/multiformats/go-multiaddr v0.11.0 + github.com/nikkolasg/hexjson v0.1.0 + github.com/prometheus/client_golang v1.16.0 + github.com/stretchr/testify v1.8.4 + github.com/urfave/cli/v2 v2.25.7 + go.opentelemetry.io/otel v1.17.0 + google.golang.org/grpc v1.57.0 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/ardanlabs/darwin/v2 v2.0.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/briandowns/spinner v1.23.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // 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 + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/drand/kyber-bls12381 v0.3.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/elastic/gosigar v0.14.2 // indirect + github.com/fatih/color v1.15.0 // 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/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-chi/chi v1.5.4 // 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.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/googleapis v1.4.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/gogo/status v1.1.1 // indirect + github.com/golang/glog v1.1.1 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/huin/goupnp v1.2.0 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/ipfs/go-datastore v0.6.0 // 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/jedib0t/go-pretty/v6 v6.4.7 // indirect + github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/kilic/bls12-381 v0.1.0 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect + github.com/lib/pq v1.10.9 // 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.3.0 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect + github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // 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.19 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.55 // 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.1 // 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-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.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.11.0 // indirect + github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect + github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-20 v0.3.2 // indirect + github.com/quic-go/quic-go v0.37.6 // indirect + github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sercand/kuberesolver/v4 v4.0.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73 // indirect + 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.etcd.io/bbolt v1.3.7 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.17.0 // indirect + go.opentelemetry.io/otel/sdk v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.17.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.0 // indirect + go.uber.org/fx v1.20.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect + google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/blake3 v1.2.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1874fcf --- /dev/null +++ b/go.sum @@ -0,0 +1,1794 @@ +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= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +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.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +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/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +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/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +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.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +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/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +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/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +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/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +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.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +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/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +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.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +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/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +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/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +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/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +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/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +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.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +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/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +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= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= +github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfKxvSy1HMhoes= +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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +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.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= +github.com/briandowns/spinner v1.23.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.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +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/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/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= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= +github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= +github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xtwfo= +github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= +github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +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/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/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +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/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +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.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/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-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-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +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= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= +github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= +github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= +github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +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= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +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-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= +github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +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= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +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/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +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.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= +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= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +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/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/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.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +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= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= +github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg= +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/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= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE= +github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +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.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/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= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M= +github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= +github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +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.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +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= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= +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.30.0 h1:9EZwFtJPFBcs/yJTnP90TpN1hgrT/EsFfM+OZuwV87U= +github.com/libp2p/go-libp2p v0.30.0/go.mod h1:nr2g5V7lfftwgiJ78/HrID+pwvayLyqKCEirT2Y3Byg= +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.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= +github.com/libp2p/go-libp2p-pubsub v0.9.3/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= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= +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-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +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/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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +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.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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +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/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/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= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10= +github.com/multiformats/go-multiaddr v0.11.0/go.mod h1:gWUm0QLR4thQ6+ZF6SXUw8YjtwQSPapICM+NmCkxHSM= +github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/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.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +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= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +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.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= +github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +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= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= +github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +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-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= +github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.37.6 h1:2IIUmQzT5YNxAiaPGjs++Z4hGOtIR0q79uS5qE9ccfY= +github.com/quic-go/quic-go v0.37.6/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU= +github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= +github.com/quic-go/webtransport-go v0.5.3/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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +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.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +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= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sercand/kuberesolver/v4 v4.0.0 h1:frL7laPDG/lFm5n98ODmWnn+cvPpzlkf3LhzuPhcHP4= +github.com/sercand/kuberesolver/v4 v4.0.0/go.mod h1:F4RGyuRmMAjeXHKL+w4P7AwUnPceEAPAhxUgXZjKgvM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +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/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= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +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/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +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-20230531151736-e2613bee6b73 h1:CMM9+/AgM77vaMXMQedzqPRMuNwjbI0EcdofPqxc9F8= +github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73/go.mod h1:rgbeLfJUtEr+G74cwFPR1k/4N0kDeaeSv/qhUNE4hm8= +github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= +github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +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.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= +go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= +go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= +go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= +go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= +go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= +go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.20.0 h1:BLOA1cZBAGSbRiNuGCCKiFrCdYB7deeHDeD1SueyOfA= +go.opentelemetry.io/proto/otlp v0.20.0/go.mod h1:3QgjzPALBIv9pcknj2EXGPXjYPFdUh/RQfF8Lz3+Vnw= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= +go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= +go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= +go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/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-20211108221036-ceb1ce70b4fa/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.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +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= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.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-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +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-20210813160813-60bc85c4be6d/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= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +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.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +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= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-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= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +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/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/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +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= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +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= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +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-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-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 h1:DEH99RbiLZhMxrpEJCZ0A+wdTe0EOgou/poSLx9vWf4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +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.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +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/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= From e99b8a62f58741be5d078cf164c3c516f9a58c71 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Mon, 4 Sep 2023 18:08:42 +0200 Subject: [PATCH 04/28] Compiling at last, in a MVP kind of way --- client/aggregator_test.go | 6 +- client/cache.go | 4 +- client/cache_test.go | 8 +- client/client.go | 2 +- client/client_test.go | 39 +- client/empty.go | 3 +- client/grpc/client.go | 142 -- client/grpc/client_test.go | 114 - client/grpc/doc.go | 43 - client/http/http.go | 3 +- client/http/http_test.go | 10 +- client/http/metric.go | 18 +- client/lp2p/client.go | 14 +- client/lp2p/client_test.go | 378 ++-- client/lp2p/validator_test.go | 50 +- client/metric.go | 53 - client/metric_test.go | 32 - client/mock/mock.go | 8 +- client/optimizing.go | 11 +- client/optimizing_test.go | 16 +- client/poll.go | 4 +- client/test/http/mock/httpserver.go | 60 +- client/test/result/mock/result.go | 16 +- client/utils_test.go | 17 +- client/verify.go | 28 +- client/verify_test.go | 14 +- client/watcher_test.go | 4 +- cmd/Dockerfile | 71 - cmd/entrypoint.sh | 27 - cmd/main.go | 209 -- go.mod | 66 +- go.sum | 1297 +----------- internal/cli.go | 320 +-- internal/cli_test.go | 3036 +++++++++++++-------------- internal/control.go | 39 - internal/lib/cli_test.go | 336 +-- internal/proposal_file.go | 124 -- internal/proposal_file_test.go | 69 - main.go | 2 +- 39 files changed, 2040 insertions(+), 4653 deletions(-) delete mode 100644 client/grpc/client.go delete mode 100644 client/grpc/client_test.go delete mode 100644 client/grpc/doc.go delete mode 100644 client/metric.go delete mode 100644 client/metric_test.go delete mode 100644 cmd/Dockerfile delete mode 100644 cmd/entrypoint.sh delete mode 100644 cmd/main.go delete mode 100644 internal/control.go delete mode 100644 internal/proposal_file.go delete mode 100644 internal/proposal_file_test.go diff --git a/client/aggregator_test.go b/client/aggregator_test.go index d70b8fe..f41c458 100644 --- a/client/aggregator_test.go +++ b/client/aggregator_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - "github.com/drand/drand-cli/internal/test/testlogger" - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/client/test/result/mock" + clientMock "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" + "github.com/drand/drand/common/testlogger" ) func TestAggregatorClose(t *testing.T) { diff --git a/client/cache.go b/client/cache.go index d153541..6fcb4e7 100644 --- a/client/cache.go +++ b/client/cache.go @@ -97,7 +97,7 @@ func (c *cachingClient) Get(ctx context.Context, round uint64) (res client.Resul } val, err := c.Client.Get(ctx, round) if err == nil && val != nil { - c.cache.Add(val.Round(), val) + c.cache.Add(val.GetRound(), val) } return val, err } @@ -107,7 +107,7 @@ func (c *cachingClient) Watch(ctx context.Context) <-chan client.Result { out := make(chan client.Result) go func() { for result := range in { - c.cache.Add(result.Round(), result) + c.cache.Add(result.GetRound(), result) out <- result } close(out) diff --git a/client/cache_test.go b/client/cache_test.go index c80dcc3..049489c 100644 --- a/client/cache_test.go +++ b/client/cache_test.go @@ -5,10 +5,10 @@ import ( "sync" "testing" - "github.com/drand/drand-cli/internal/test/testlogger" - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/client/test/result/mock" + clientMock "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" + "github.com/drand/drand/common/testlogger" ) func TestCacheGet(t *testing.T) { @@ -72,7 +72,7 @@ func TestCacheGetLatest(t *testing.T) { t.Fatal(e) } - if r0.Round() == r1.Round() { + if r0.GetRound() == r1.GetRound() { t.Fatal("cached result for latest") } } diff --git a/client/client.go b/client/client.go index a63210c..a602c5e 100644 --- a/client/client.go +++ b/client/client.go @@ -269,7 +269,7 @@ func WithChainInfo(chainInfo *chain.Info) Option { // previously not-yet-verified results. func WithVerifiedResult(result client.Result) Option { return func(cfg *clientConfig) error { - if cfg.previousResult != nil && cfg.previousResult.Round() > result.Round() { + if cfg.previousResult != nil && cfg.previousResult.GetRound() > result.GetRound() { return errors.New("refusing to override verified result with an earlier result") } cfg.previousResult = result diff --git a/client/client_test.go b/client/client_test.go index 4a968d6..02811de 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -3,21 +3,21 @@ package client_test import ( "context" "errors" + "github.com/drand/drand/common/key" "testing" "time" clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" - "github.com/drand/drand-cli/internal/test" - "github.com/drand/drand-cli/internal/test/testlogger" - client2 "github.com/drand/drand/client" - "github.com/drand/drand/client/http" - clientMock "github.com/drand/drand/client/mock" - httpmock "github.com/drand/drand/client/test/http/mock" - "github.com/drand/drand/client/test/result/mock" + client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/http" + clientMock "github.com/drand/drand-cli/client/mock" + httpmock "github.com/drand/drand-cli/client/test/http/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" + "github.com/drand/drand/common/testlogger" "github.com/drand/drand/crypto" ) @@ -77,7 +77,7 @@ func TestClientMultiple(t *testing.T) { if e != nil { t.Fatal(e) } - if r.Round() <= 0 { + if r.GetRound() <= 0 { t.Fatal("expected valid client") } _ = c.Close() @@ -89,13 +89,7 @@ func TestClientWithChainInfo(t *testing.T) { } ctx := context.Background() - id := test.GenerateIDs(1)[0] - chainInfo := &chain.Info{ - PublicKey: id.Public.Key, - GenesisTime: 100, - Period: time.Second, - Scheme: crypto.DefaultSchemeID, - } + chainInfo := fakeChainInfo(t) lg := testlogger.New(t) hc, err := http.NewWithInfo(lg, "http://nxdomain.local/", chainInfo, nil) require.NoError(t, err) @@ -139,7 +133,7 @@ func TestClientCache(t *testing.T) { t.Fatal(e) } cancel() - _, e = c.Get(ctx, r0.Round()) + _, e = c.Get(ctx, r0.GetRound()) if e != nil { t.Fatal(e) } @@ -327,7 +321,7 @@ func TestClientAutoWatch(t *testing.T) { time.Sleep(chainInfo.Period) cancel() - r, err := c.Get(ctx, results[0].Round()) + r, err := c.Get(ctx, results[0].GetRound()) if err != nil { t.Fatal(err) } @@ -400,7 +394,7 @@ func TestClientAutoWatchRetry(t *testing.T) { // We should be able to retrieve all the results from the cache. for i := range results { - r, err := c.Get(ctx, results[i].Round()) + r, err := c.Get(ctx, results[i].GetRound()) if err != nil { t.Fatal(err) } @@ -414,8 +408,8 @@ func compareResults(t *testing.T, expected, actual client.Result) { require.NotNil(t, expected) require.NotNil(t, actual) - require.Equal(t, expected.Round(), actual.Round()) - require.Equal(t, expected.Randomness(), actual.Randomness()) + require.Equal(t, expected.GetRound(), actual.GetRound()) + require.Equal(t, expected.GetRandomness(), actual.GetRandomness()) } // fakeChainInfo creates a chain info object for use in tests. @@ -423,10 +417,13 @@ func fakeChainInfo(t *testing.T) *chain.Info { t.Helper() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) + pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) + require.NoError(t, err) + return &chain.Info{ Period: time.Second, GenesisTime: time.Now().Unix(), - PublicKey: test.GenerateIDs(1)[0].Public.Key, + PublicKey: pair.Public.Key, Scheme: sch.Name, } } diff --git a/client/empty.go b/client/empty.go index 00a0581..cd987ac 100644 --- a/client/empty.go +++ b/client/empty.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/drand/drand-cli/internal/chain" "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" @@ -30,7 +29,7 @@ func (m *emptyClient) Info(_ context.Context) (*chain2.Info, error) { } func (m *emptyClient) RoundAt(t time.Time) uint64 { - return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) + return common.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) } func (m *emptyClient) Get(_ context.Context, _ uint64) (client.Result, error) { diff --git a/client/grpc/client.go b/client/grpc/client.go deleted file mode 100644 index 4533fef..0000000 --- a/client/grpc/client.go +++ /dev/null @@ -1,142 +0,0 @@ -package grpc - -import ( - "context" - "crypto/tls" - "errors" - "fmt" - "github.com/drand/drand-cli/client" - commonutils "github.com/drand/drand/common" - "time" - - grpcProm "github.com/grpc-ecosystem/go-grpc-prometheus" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - grpcInsec "google.golang.org/grpc/credentials/insecure" - - chain2 "github.com/drand/drand/common/chain" - client2 "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/protobuf/common" - "github.com/drand/drand/protobuf/drand" -) - -const grpcDefaultTimeout = 5 * time.Second - -type grpcClient struct { - address string - chainHash []byte - client drand.PublicClient - conn *grpc.ClientConn - l log.Logger -} - -// New creates a drand client backed by a GRPC connection. -func New(l log.Logger, address string, insecure bool, chainHash []byte) (client2.Client, error) { - var opts []grpc.DialOption - if insecure { - opts = append(opts, grpc.WithTransportCredentials(grpcInsec.NewCredentials())) - } else { - opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}))) - } - opts = append(opts, - grpc.WithUnaryInterceptor(grpcProm.UnaryClientInterceptor), - grpc.WithStreamInterceptor(grpcProm.StreamClientInterceptor), - ) - conn, err := grpc.Dial(address, opts...) - if err != nil { - return nil, err - } - - return &grpcClient{address, chainHash, drand.NewPublicClient(conn), conn, l}, nil -} - -func asRD(r *drand.PublicRandResponse) *client.RandomData { - return &client.RandomData{ - Rnd: r.Round, - Random: r.Randomness, - Sig: r.Signature, - PreviousSignature: r.PreviousSignature, - } -} - -// String returns the name of this client. -func (g *grpcClient) String() string { - return fmt.Sprintf("GRPC(%q)", g.address) -} - -// Get returns the randomness at `round` or an error. -func (g *grpcClient) Get(ctx context.Context, round uint64) (client2.Result, error) { - curr, err := g.client.PublicRand(ctx, &drand.PublicRandRequest{Round: round, Metadata: g.getMetadata()}) - if err != nil { - return nil, err - } - if curr == nil { - return nil, errors.New("no received randomness - unexpected gPRC response") - } - - return asRD(curr), nil -} - -// Watch returns new randomness as it becomes available. -func (g *grpcClient) Watch(ctx context.Context) <-chan client2.Result { - stream, err := g.client.PublicRandStream(ctx, &drand.PublicRandRequest{Round: 0, Metadata: g.getMetadata()}) - ch := make(chan client2.Result, 1) - if err != nil { - close(ch) - return ch - } - go g.translate(stream, ch) - return ch -} - -// Info returns information about the chain. -func (g *grpcClient) Info(ctx context.Context) (*chain2.Info, error) { - proto, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) - if err != nil { - return nil, err - } - if proto == nil { - return nil, errors.New("no received group - unexpected gPRC response") - } - return chain2.InfoFromProto(proto) -} - -func (g *grpcClient) translate(stream drand.Public_PublicRandStreamClient, out chan<- client2.Result) { - defer close(out) - for { - next, err := stream.Recv() - if err != nil || stream.Context().Err() != nil { - if stream.Context().Err() == nil { - g.l.Warnw("", "grpc_client", "public rand stream", "err", err) - } - return - } - out <- asRD(next) - } -} - -func (g *grpcClient) getMetadata() *common.Metadata { - return &common.Metadata{ChainHash: g.chainHash} -} - -func (g *grpcClient) RoundAt(t time.Time) uint64 { - ctx, cancel := context.WithTimeout(context.Background(), grpcDefaultTimeout) - defer cancel() - - info, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) - if err != nil { - return 0 - } - return commonutils.CurrentRound(t.Unix(), time.Second*time.Duration(info.Period), info.GenesisTime) -} - -// SetLog configures the client log output -func (g *grpcClient) SetLog(l log.Logger) { - g.l = l -} - -// Close tears down the gRPC connection and all underlying connections. -func (g *grpcClient) Close() error { - return g.conn.Close() -} diff --git a/client/grpc/client_test.go b/client/grpc/client_test.go deleted file mode 100644 index dbd1266..0000000 --- a/client/grpc/client_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package grpc - -import ( - "bytes" - "context" - "sync" - "testing" - "time" - - clock "github.com/jonboulle/clockwork" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/drand/drand-cli/internal/test/mock" - "github.com/drand/drand-cli/internal/test/testlogger" - "github.com/drand/drand/crypto" -) - -func TestClient(t *testing.T) { - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - clk := clock.NewFakeClockAt(time.Now()) - l, server := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) - addr := l.Addr() - - go l.Start() - defer l.Stop(context.Background()) - - c, err := New(lg, addr, "", true, []byte("")) - if err != nil { - t.Fatal(err) - } - result, err := c.Get(context.Background(), 1969) - if err != nil { - t.Fatal(err) - } - if result.Round() != 1969 { - t.Fatal("unexpected round.") - } - r2, err := c.Get(context.Background(), 1970) - if err != nil { - t.Fatal(err) - } - if bytes.Equal(r2.Randomness(), result.Randomness()) { - t.Fatal("unexpected equality") - } - - rat := c.RoundAt(time.Now()) - if rat == 0 { - t.Fatal("round at should function") - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - res := c.Watch(ctx) - go func() { - time.Sleep(50 * time.Millisecond) - server.(mock.Service).EmitRand(false) - }() - r3, ok := <-res - if !ok { - t.Fatal("watch should work") - } - if r3.Round() != 1971 { - t.Fatal("unexpected round") - } - cancel() - _ = c.Close() -} - -func TestClientClose(t *testing.T) { - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - clk := clock.NewFakeClockAt(time.Now()) - l, _ := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) - addr := l.Addr() - - go l.Start() - defer l.Stop(context.Background()) - - c, err := New(lg, addr, "", true, []byte("")) - if err != nil { - t.Fatal(err) - } - result, err := c.Get(context.Background(), 1969) - if err != nil { - t.Fatal(err) - } - if result.Round() != 1969 { - t.Fatal("unexpected round.") - } - - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - for range c.Watch(context.Background()) { - } - wg.Done() - }() - - err = c.Close() - if err != nil { - t.Fatal(err) - } - - _, err = c.Get(context.Background(), 0) - if status.Code(err) != codes.Canceled { - t.Fatal("unexpected error from closed client", err) - } - - wg.Wait() // wait for the watch to close -} diff --git a/client/grpc/doc.go b/client/grpc/doc.go deleted file mode 100644 index 6bb4ae3..0000000 --- a/client/grpc/doc.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Package grpc provides a drand client implementation that uses drand's gRPC API. - -The client connects to a drand gRPC endpoint to fetch randomness. The gRPC -client has some advantages over the HTTP client - it is more compact -on-the-wire and supports streaming and authentication. - -Example: - - package main - - import ( - "context" - "encoding/hex" - - "github.com/drand/drand/client" - "github.com/drand/drand/client/grpc" - "github.com/drand/drand/common/log" - ) - - const ( - grpcAddr = "example.drand.grpc.server:4444" - certPath = "/path/to/drand-grpc.cert" - ) - - var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") - - func main() { - ctx := context.Background() - lg := log.New(nil, log.DebugLevel, true) - - gc, err := grpc.New(lg, grpcAddr, certPath, false, chainHash) - - c, err := client.New(ctx, lg, - client.From(gc), - ) - } - -A path to a file that holds TLS credentials for the drand server is required -to validate server connections. Alternatively set the final parameter to -`true` to enable _insecure_ connections (not recommended). -*/ -package grpc diff --git a/client/http/http.go b/client/http/http.go index 37e8a1f..28ff0db 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -5,6 +5,7 @@ import ( "context" "encoding/hex" "fmt" + client2 "github.com/drand/drand-cli/client" nhttp "net/http" "os" "path" @@ -362,7 +363,7 @@ func (h *httpClient) Info(_ context.Context) (*chain2.Info, error) { // RoundAt will return the most recent round of randomness that will be available // at time for the current client. func (h *httpClient) RoundAt(t time.Time) uint64 { - return chain.CurrentRound(t.Unix(), h.chainInfo.Period, h.chainInfo.GenesisTime) + return common.CurrentRound(t.Unix(), h.chainInfo.Period, h.chainInfo.GenesisTime) } func (h *httpClient) Close() error { diff --git a/client/http/http_test.go b/client/http/http_test.go index 35981a1..f18092b 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -5,6 +5,8 @@ import ( "encoding/json" "errors" "fmt" + "github.com/drand/drand/common/log" + "github.com/drand/drand/protobuf/drand" "net" "net/http" "sync" @@ -14,9 +16,9 @@ import ( clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" - "github.com/drand/drand-cli/internal/test/testlogger" - "github.com/drand/drand/client" - "github.com/drand/drand/client/test/http/mock" + "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/test/http/mock" + "github.com/drand/drand/common/testlogger" "github.com/drand/drand/crypto" ) @@ -45,7 +47,7 @@ func TestHTTPClient(t *testing.T) { if err != nil { t.Fatal(err) } - if len(result.Randomness()) == 0 { + if len(result.GetRandomness()) == 0 { t.Fatal("no randomness provided") } full, ok := (result).(*client.RandomData) diff --git a/client/http/metric.go b/client/http/metric.go index 0ff000a..af8aa31 100644 --- a/client/http/metric.go +++ b/client/http/metric.go @@ -2,12 +2,10 @@ package http import ( "context" + "fmt" + "github.com/drand/drand/common" "time" - "github.com/prometheus/client_golang/prometheus" - - "github.com/drand/drand-cli/internal/chain" - "github.com/drand/drand-cli/internal/metrics" chain2 "github.com/drand/drand/common/client" ) @@ -32,6 +30,7 @@ type HealthMetrics struct { // HeartbeatInterval is the duration between liveness heartbeats sent to an HTTP API. const HeartbeatInterval = 10 * time.Second +// TODO add metrics back in func (c *HealthMetrics) startObserve(ctx context.Context) { for { select { @@ -50,18 +49,19 @@ func (c *HealthMetrics) startObserve(ctx context.Context) { result, err := c.clients[n].Get(ctx, c.clients[n].RoundAt(time.Now())+1) if err != nil { - metrics.ClientHTTPHeartbeatFailure.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + //metrics.ClientHTTPHeartbeatFailure.With(prometheus.Labels{"http_address": httpClient.root}).Inc() continue } - metrics.ClientHTTPHeartbeatSuccess.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + //metrics.ClientHTTPHeartbeatSuccess.With(prometheus.Labels{"http_address": httpClient.root}).Inc() // compute the latency metric actual := time.Now().UnixNano() - expected := chain.TimeOfRound(httpClient.chainInfo.Period, httpClient.chainInfo.GenesisTime, result.Round()) * 1e9 + expected := common.TimeOfRound(httpClient.chainInfo.Period, httpClient.chainInfo.GenesisTime, result.GetRound()) * 1e9 // the labels of the gauge vec must already be set at the registerer level - metrics.ClientHTTPHeartbeatLatency.With(prometheus.Labels{"http_address": httpClient.root}). - Set(float64(actual-expected) / float64(time.Millisecond)) + //metrics.ClientHTTPHeartbeatLatency.With(prometheus.Labels{"http_address": httpClient.root}). + // Set(float64(actual-expected) / float64(time.Millisecond)) + fmt.Println(float64(actual-expected) / float64(time.Millisecond)) c.next++ } } diff --git a/client/lp2p/client.go b/client/lp2p/client.go index 70a1294..425dfdd 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -13,8 +13,7 @@ import ( "github.com/multiformats/go-multiaddr" "google.golang.org/protobuf/proto" - "github.com/drand/drand-cli/internal/lp2p" - client2 "github.com/drand/drand/client" + client2 "github.com/drand/drand-cli/client" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" @@ -56,6 +55,11 @@ func WithPubsub(l log.Logger, ps *pubsub.PubSub, clk clock.Clock, bufferSize int }) } +// PubSubTopic generates a drand pubsub topic from a chain hash. +func PubSubTopic(h string) string { + return fmt.Sprintf("/drand/pubsub/v0.0.0/%s", h) +} + // NewWithPubsub creates a gossip randomness client. // //nolint:funlen,lll // This is the correct function length @@ -73,7 +77,7 @@ func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache clie } chainHash := hex.EncodeToString(info.Hash()) - topic := lp2p.PubSubTopic(chainHash) + topic := PubSubTopic(chainHash) if err := ps.RegisterTopicValidator(topic, randomnessValidator(info, cache, c, clk)); err != nil { cancel() return nil, fmt.Errorf("creating topic: %w", err) @@ -205,9 +209,9 @@ func (c *Client) Watch(ctx context.Context) <-chan client.Result { } select { case outerCh <- dat: - c.log.Debugw("processed random beacon", "round", dat.Round()) + c.log.Debugw("processed random beacon", "round", dat.GetRound()) default: - c.log.Warnw("", "gossip client", "randomness notification dropped due to a full channel", "round", dat.Round()) + c.log.Warnw("", "gossip client", "randomness notification dropped due to a full channel", "round", dat.GetRound()) } case <-ctx.Done(): c.log.Debugw("client.Watch done") diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index b61e3ec..19e4ff5 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -1,110 +1,95 @@ package lp2p import ( - "context" "fmt" - "net/http" - "path" "testing" "time" - bds "github.com/ipfs/go-ds-badger2" - clock "github.com/jonboulle/clockwork" + "github.com/drand/drand/common/client" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" - "github.com/stretchr/testify/require" - - "github.com/drand/drand-cli/internal/lp2p" - "github.com/drand/drand-cli/internal/test" - "github.com/drand/drand-cli/internal/test/mock" - "github.com/drand/drand-cli/internal/test/testlogger" - "github.com/drand/drand/client/grpc" - dhttp "github.com/drand/drand/client/http" - httpmock "github.com/drand/drand/client/test/http/mock" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/crypto" ) -func TestGRPCClientTestFunc(t *testing.T) { - lg := testlogger.New(t) - // start mock drand node - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - - clk := clock.NewFakeClockAt(time.Now()) - - grpcLis, svc := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) - grpcAddr := grpcLis.Addr() - go grpcLis.Start() - defer grpcLis.Stop(context.Background()) - - dataDir := t.TempDir() - identityDir := t.TempDir() - - infoProto, err := svc.ChainInfo(context.Background(), nil) - require.NoError(t, err) - - info, err := chain2.InfoFromProto(infoProto) - require.NoError(t, err) - - // start mock relay-node - grpcClient, err := grpc.New(lg, grpcAddr, "", true, []byte("")) - require.NoError(t, err) - - cfg := &lp2p.GossipRelayConfig{ - ChainHash: info.HashString(), - PeerWith: nil, - Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), - DataDir: dataDir, - IdentityPath: path.Join(identityDir, "identity.key"), - Client: grpcClient, - } - g, err := lp2p.NewGossipRelayNode(lg, cfg) - require.NoError(t, err, "gossip relay node") - - defer g.Shutdown() - - // start client - c, err := newTestClient(t, g.Multiaddrs(), info, clk) - require.NoError(t, err) - defer func() { - err := c.Close() - require.NoError(t, err) - }() - - // test client - ctx, cancel := context.WithCancel(context.Background()) - ch := c.Watch(ctx) - - baseRound := uint64(1969) - - mockService := svc.(mock.Service) - // pub sub polls every 200ms - wait := 250 * time.Millisecond - for i := uint64(0); i < 3; i++ { - time.Sleep(wait) - mockService.EmitRand(false) - t.Logf("round %d emitted\n", baseRound+i) - - select { - case r, ok := <-ch: - require.True(t, ok, "expected randomness, watch outer channel was closed instead") - t.Logf("received round %d\n", r.Round()) - require.Equal(t, baseRound+i, r.Round()) - // the period of the mock servers is 1 second - case <-time.After(5 * time.Second): - t.Fatal("timeout.") - } - } - - time.Sleep(wait) - mockService.EmitRand(true) - cancel() - - drain(t, ch, 5*time.Second) -} +// +//func TestGRPCClientTestFunc(t *testing.T) { +// lg := testlogger.New(t) +// // start mock drand node +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// +// clk := clock.NewFakeClockAt(time.Now()) +// +// grpcLis, svc := mock.NewMockGRPCPublicServer(t, lg, "127.0.0.1:0", false, sch, clk) +// grpcAddr := grpcLis.Addr() +// go grpcLis.Start() +// defer grpcLis.Stop(context.Background()) +// +// dataDir := t.TempDir() +// identityDir := t.TempDir() +// +// infoProto, err := svc.ChainInfo(context.Background(), nil) +// require.NoError(t, err) +// +// info, err := chain2.InfoFromProto(infoProto) +// require.NoError(t, err) +// +// // start mock relay-node +// grpcClient, err := grpc.New(lg, grpcAddr, "", true, []byte("")) +// require.NoError(t, err) +// +// cfg := &lp2p.GossipRelayConfig{ +// ChainHash: info.HashString(), +// PeerWith: nil, +// Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), +// DataDir: dataDir, +// IdentityPath: path.Join(identityDir, "identity.key"), +// Client: grpcClient, +// } +// g, err := lp2p.NewGossipRelayNode(lg, cfg) +// require.NoError(t, err, "gossip relay node") +// +// defer g.Shutdown() +// +// // start client +// c, err := newTestClient(t, g.Multiaddrs(), info, clk) +// require.NoError(t, err) +// defer func() { +// err := c.Close() +// require.NoError(t, err) +// }() +// +// // test client +// ctx, cancel := context.WithCancel(context.Background()) +// ch := c.Watch(ctx) +// +// baseRound := uint64(1969) +// +// mockService := svc.(mock.Service) +// // pub sub polls every 200ms +// wait := 250 * time.Millisecond +// for i := uint64(0); i < 3; i++ { +// time.Sleep(wait) +// mockService.EmitRand(false) +// t.Logf("round %d emitted\n", baseRound+i) +// +// select { +// case r, ok := <-ch: +// require.True(t, ok, "expected randomness, watch outer channel was closed instead") +// t.Logf("received round %d\n", r.Round()) +// require.Equal(t, baseRound+i, r.Round()) +// // the period of the mock servers is 1 second +// case <-time.After(5 * time.Second): +// t.Fatal("timeout.") +// } +// } +// +// time.Sleep(wait) +// mockService.EmitRand(true) +// cancel() +// +// drain(t, ch, 5*time.Second) +//} func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { for { @@ -119,107 +104,108 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { } } -func TestHTTPClientTestFunc(t *testing.T) { - if testing.Short() { - t.Skip("skipping slow test in short mode.") - } - - ctx := context.Background() - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - - clk := clock.NewFakeClockAt(time.Now()) - - addr, chainInfo, stop, emit := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) - defer stop() - - dataDir := t.TempDir() - identityDir := t.TempDir() - - httpClient, err := dhttp.New(ctx, lg, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) - require.NoError(t, err) - - cfg := &lp2p.GossipRelayConfig{ - ChainHash: chainInfo.HashString(), - PeerWith: nil, - Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), - DataDir: dataDir, - IdentityPath: path.Join(identityDir, "identity.key"), - Client: httpClient, - } - g, err := lp2p.NewGossipRelayNode(lg, cfg) - if err != nil { - t.Fatalf("gossip relay node (%v)", err) - } - defer g.Shutdown() - - c, err := newTestClient(t, g.Multiaddrs(), chainInfo, clk) - if err != nil { - t.Fatal(err) - } - defer c.Close() - - ctx, cancel := context.WithCancel(ctx) - emit(false) - ch := c.Watch(ctx) - for i := 0; i < 3; i++ { - // pub sub polls every 200ms, but the other http one polls every period - time.Sleep(1250 * time.Millisecond) - emit(false) - select { - case r, ok := <-ch: - if !ok { - t.Fatal("expected randomness") - } else { - t.Log("received randomness", r.Round()) - } - case <-time.After(8 * time.Second): - t.Fatal("timeout.") - } - } - emit(true) - cancel() - drain(t, ch, 5*time.Second) -} - -func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { - dataDir := t.TempDir() - identityDir := t.TempDir() - ds, err := bds.NewDatastore(dataDir, nil) - if err != nil { - return nil, err - } - lg := testlogger.New(t) - priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) - if err != nil { - return nil, err - } - h, ps, err := lp2p.ConstructHost( - ds, - priv, - "/ip4/0.0.0.0/tcp/"+test.FreePort(), - relayMultiaddr, - lg, - ) - if err != nil { - return nil, err - } - relayPeerID, err := peerIDFromMultiaddr(relayMultiaddr[0]) - if err != nil { - return nil, err - } - err = waitForConnection(h, relayPeerID, time.Minute) - if err != nil { - return nil, err - } - c, err := NewWithPubsub(lg, ps, info, nil, clk, 100) - if err != nil { - return nil, err - } - c.SetLog(lg) - return c, nil -} +// +//func TestHTTPClientTestFunc(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping slow test in short mode.") +// } +// +// ctx := context.Background() +// lg := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// +// clk := clock.NewFakeClockAt(time.Now()) +// +// addr, chainInfo, stop, emit := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) +// defer stop() +// +// dataDir := t.TempDir() +// identityDir := t.TempDir() +// +// httpClient, err := dhttp.New(ctx, lg, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) +// require.NoError(t, err) +// +// cfg := &lp2p.GossipRelayConfig{ +// ChainHash: chainInfo.HashString(), +// PeerWith: nil, +// Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), +// DataDir: dataDir, +// IdentityPath: path.Join(identityDir, "identity.key"), +// Client: httpClient, +// } +// g, err := lp2p.NewGossipRelayNode(lg, cfg) +// if err != nil { +// t.Fatalf("gossip relay node (%v)", err) +// } +// defer g.Shutdown() +// +// c, err := newTestClient(t, g.Multiaddrs(), chainInfo, clk) +// if err != nil { +// t.Fatal(err) +// } +// defer c.Close() +// +// ctx, cancel := context.WithCancel(ctx) +// emit(false) +// ch := c.Watch(ctx) +// for i := 0; i < 3; i++ { +// // pub sub polls every 200ms, but the other http one polls every period +// time.Sleep(1250 * time.Millisecond) +// emit(false) +// select { +// case r, ok := <-ch: +// if !ok { +// t.Fatal("expected randomness") +// } else { +// t.Log("received randomness", r.GetRound()) +// } +// case <-time.After(8 * time.Second): +// t.Fatal("timeout.") +// } +// } +// emit(true) +// cancel() +// drain(t, ch, 5*time.Second) +//} + +//func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { +// dataDir := t.TempDir() +// identityDir := t.TempDir() +// ds, err := bds.NewDatastore(dataDir, nil) +// if err != nil { +// return nil, err +// } +// lg := testlogger.New(t) +// priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) +// if err != nil { +// return nil, err +// } +// h, ps, err := lp2p.ConstructHost( +// ds, +// priv, +// "/ip4/0.0.0.0/tcp/"+test.FreePort(), +// relayMultiaddr, +// lg, +// ) +// if err != nil { +// return nil, err +// } +// relayPeerID, err := peerIDFromMultiaddr(relayMultiaddr[0]) +// if err != nil { +// return nil, err +// } +// err = waitForConnection(h, relayPeerID, time.Minute) +// if err != nil { +// return nil, err +// } +// c, err := NewWithPubsub(lg, ps, info, nil, clk, 100) +// if err != nil { +// return nil, err +// } +// c.SetLog(lg) +// return c, nil +//} func peerIDFromMultiaddr(addr ma.Multiaddr) (peer.ID, error) { ai, err := peer.AddrInfoFromP2pAddr(addr) diff --git a/client/lp2p/validator_test.go b/client/lp2p/validator_test.go index 90fe032..684d780 100644 --- a/client/lp2p/validator_test.go +++ b/client/lp2p/validator_test.go @@ -6,6 +6,8 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/drand/drand/common" + "github.com/drand/drand/common/key" "testing" "time" @@ -16,12 +18,10 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "google.golang.org/protobuf/proto" - "github.com/drand/drand-cli/internal/chain" - "github.com/drand/drand-cli/internal/test" - "github.com/drand/drand-cli/internal/test/testlogger" - "github.com/drand/drand/client" - "github.com/drand/drand/client/test/cache" + "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/test/cache" chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/testlogger" dcrypto "github.com/drand/drand/crypto" "github.com/drand/drand/protobuf/drand" ) @@ -30,15 +30,15 @@ type randomDataWrapper struct { data client.RandomData } -func (r *randomDataWrapper) Round() uint64 { +func (r *randomDataWrapper) GetRound() uint64 { return r.data.Rnd } -func (r *randomDataWrapper) Signature() []byte { +func (r *randomDataWrapper) GetSignature() []byte { return r.data.Sig } -func (r *randomDataWrapper) Randomness() []byte { +func (r *randomDataWrapper) GetRandomness() []byte { return r.data.Random } @@ -55,7 +55,7 @@ func randomPeerID(t *testing.T) peer.ID { } func fakeRandomData(info *chain2.Info, clk clock.Clock) client.RandomData { - rnd := chain.CurrentRound(clk.Now().Unix(), info.Period, info.GenesisTime) + rnd := common.CurrentRound(clk.Now().Unix(), info.Period, info.GenesisTime) sig := make([]byte, 8) binary.LittleEndian.PutUint64(sig, rnd) @@ -71,10 +71,20 @@ func fakeRandomData(info *chain2.Info, clk clock.Clock) client.RandomData { } func fakeChainInfo() *chain2.Info { + sch, err := dcrypto.GetSchemeFromEnv() + if err != nil { + panic(err) + } + pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) + if err != nil { + panic(err) + } + return &chain2.Info{ Period: time.Second, GenesisTime: time.Now().Unix(), - PublicKey: test.GenerateIDs(1)[0].Public.Key, + PublicKey: pair.Public.Key, + Scheme: sch.Name, } } @@ -116,7 +126,7 @@ func TestRejectsFutureBeacons(t *testing.T) { validate := randomnessValidator(info, nil, &c, clk) resp := drand.PublicRandResponse{ - Round: chain.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime) + 5, + Round: common.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime) + 5, } data, err := proto.Marshal(&resp) if err != nil { @@ -137,7 +147,7 @@ func TestRejectsVerifyBeaconFailure(t *testing.T) { validate := randomnessValidator(info, nil, &c, clk) resp := drand.PublicRandResponse{ - Round: chain.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime), + Round: common.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime), // missing signature etc. } data, err := proto.Marshal(&resp) @@ -219,13 +229,13 @@ func TestIgnoresCachedEqualNonRandomDataBeacon(t *testing.T) { validate := randomnessValidator(info, ca, &c, clk) rdata := randomDataWrapper{fakeRandomData(info, clk)} - ca.Add(rdata.Round(), &rdata) + ca.Add(rdata.GetRound(), &rdata) resp := drand.PublicRandResponse{ - Round: rdata.Round(), - Signature: rdata.Signature(), + Round: rdata.GetRound(), + Signature: rdata.GetSignature(), PreviousSignature: rdata.data.PreviousSignature, - Randomness: rdata.Randomness(), + Randomness: rdata.GetRandomness(), } data, err := proto.Marshal(&resp) if err != nil { @@ -247,16 +257,16 @@ func TestRejectsCachedEqualNonRandomDataBeacon(t *testing.T) { validate := randomnessValidator(info, ca, &c, clk) rdata := randomDataWrapper{fakeRandomData(info, clk)} - ca.Add(rdata.Round(), &rdata) + ca.Add(rdata.GetRound(), &rdata) sig := make([]byte, 8) - binary.LittleEndian.PutUint64(sig, rdata.Round()+1) + binary.LittleEndian.PutUint64(sig, rdata.GetRound()+1) resp := drand.PublicRandResponse{ - Round: rdata.Round(), + Round: rdata.GetRound(), Signature: sig, // incoming message has incorrect sig PreviousSignature: rdata.data.PreviousSignature, - Randomness: rdata.Randomness(), + Randomness: rdata.GetRandomness(), } data, err := proto.Marshal(&resp) if err != nil { diff --git a/client/metric.go b/client/metric.go deleted file mode 100644 index a93a4ab..0000000 --- a/client/metric.go +++ /dev/null @@ -1,53 +0,0 @@ -package client - -import ( - "context" - "time" - - "github.com/drand/drand-cli/internal/chain" - "github.com/drand/drand-cli/internal/metrics" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" -) - -func newWatchLatencyMetricClient(base client.Client, info *chain2.Info) client.Client { - ctx, cancel := context.WithCancel(context.Background()) - c := &watchLatencyMetricClient{ - Client: base, - chainInfo: info, - cancel: cancel, - } - go c.startObserve(ctx) - return c -} - -type watchLatencyMetricClient struct { - client.Client - chainInfo *chain2.Info - cancel context.CancelFunc -} - -func (c *watchLatencyMetricClient) startObserve(ctx context.Context) { - rch := c.Watch(ctx) - for { - select { - case result, ok := <-rch: - if !ok { - return - } - // compute the latency metric - actual := time.Now().UnixNano() - expected := chain.TimeOfRound(c.chainInfo.Period, c.chainInfo.GenesisTime, result.Round()) * 1e9 - // the labels of the gauge vec must already be set at the registerer level - metrics.ClientWatchLatency.Set(float64(actual-expected) / float64(time.Millisecond)) - case <-ctx.Done(): - return - } - } -} - -func (c *watchLatencyMetricClient) Close() error { - err := c.Client.Close() - c.cancel() - return err -} diff --git a/client/metric_test.go b/client/metric_test.go deleted file mode 100644 index e2311ce..0000000 --- a/client/metric_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package client - -import ( - "sync" - "testing" - - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/common/client" -) - -func TestMetricClose(t *testing.T) { - chainInfo := fakeChainInfo(t) - wg := sync.WaitGroup{} - wg.Add(1) - - c := &clientMock.Client{ - WatchCh: make(chan client.Result), - CloseF: func() error { - wg.Done() - return nil - }, - } - - mc := newWatchLatencyMetricClient(c, chainInfo) - - err := mc.Close() // should close the underlying client - if err != nil { - t.Fatal(err) - } - - wg.Wait() // wait for underlying client to close -} diff --git a/client/mock/mock.go b/client/mock/mock.go index fb6e945..74ee5c0 100644 --- a/client/mock/mock.go +++ b/client/mock/mock.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/drand/drand-cli/internal/chain" - "github.com/drand/drand/client/test/result/mock" + "github.com/drand/drand-cli/client/test/result/mock" + commonutils "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" ) @@ -48,7 +48,7 @@ func (m *Client) Get(ctx context.Context, round uint64) (client.Result, error) { r := m.Results[0] if m.StrictRounds { for _, candidate := range m.Results { - if candidate.Round() == round { + if candidate.GetRound() == round { r = candidate break } @@ -134,7 +134,7 @@ func (m *InfoClient) Info(_ context.Context) (*chain2.Info, error) { } func (m *InfoClient) RoundAt(t time.Time) uint64 { - return chain.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) + return commonutils.CurrentRound(t.Unix(), m.i.Period, m.i.GenesisTime) } func (m *InfoClient) Get(_ context.Context, _ uint64) (client.Result, error) { diff --git a/client/optimizing.go b/client/optimizing.go index a8b20d5..8c06c18 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -12,9 +12,8 @@ import ( "github.com/hashicorp/go-multierror" - "github.com/drand/drand-cli/internal/chain" "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" ) @@ -381,13 +380,13 @@ type watchResult struct { client.Client } -func (oc *optimizingClient) trackWatchResults(info *chain2.Info, in chan watchResult, out chan client.Result) { +func (oc *optimizingClient) trackWatchResults(info *chain.Info, in chan watchResult, out chan client.Result) { defer close(out) latest := uint64(0) for r := range in { - round := r.Result.Round() - timeOfRound := time.Unix(chain.TimeOfRound(info.Period, info.GenesisTime, round), 0) + round := r.Result.GetRound() + timeOfRound := time.Unix(common.TimeOfRound(info.Period, info.GenesisTime, round), 0) stat := requestStat{ client: r.Client, rtt: time.Since(timeOfRound), @@ -610,7 +609,7 @@ ClientLoop: // Info returns the parameters of the chain this client is connected to. // The public key, when it started, and how frequently it updates. -func (oc *optimizingClient) Info(ctx context.Context) (chainInfo *chain2.Info, err error) { +func (oc *optimizingClient) Info(ctx context.Context) (chainInfo *chain.Info, err error) { clients := oc.fastestClients() for _, c := range clients { ctx, cancel := context.WithTimeout(ctx, oc.requestTimeout) diff --git a/client/optimizing_test.go b/client/optimizing_test.go index f7e7efb..b968289 100644 --- a/client/optimizing_test.go +++ b/client/optimizing_test.go @@ -2,13 +2,13 @@ package client import ( "context" + "github.com/drand/drand/common/testlogger" "sync" "testing" "time" - "github.com/drand/drand-cli/internal/test/testlogger" - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/client/test/result/mock" + clientMock "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" ) @@ -51,8 +51,8 @@ func waitForSpeedTest(t *testing.T, c client.Client, timeout time.Duration) { func expectRound(t *testing.T, res client.Result, r uint64) { t.Helper() - if res.Round() != r { - t.Fatalf("expected round %v, got %v", r, res.Round()) + if res.GetRound() != r { + t.Fatalf("expected round %v, got %v", r, res.GetRound()) } } @@ -159,7 +159,7 @@ func TestOptimizingWatchRetryOnClose(t *testing.T) { var i uint64 for r := range ch { - if r.Round() != i { + if r.GetRound() != i { t.Fatal("unexpected round number") } i++ @@ -211,8 +211,8 @@ func TestOptimizingWatchFailover(t *testing.T) { var i uint64 = 1 for r := range ch { - if r.Round() != i { - t.Fatalf("unexpected round number %d vs %d", r.Round(), i) + if r.GetRound() != i { + t.Fatalf("unexpected round number %d vs %d", r.GetRound(), i) } i++ if i > 5 { diff --git a/client/poll.go b/client/poll.go index 67bc8a9..2dabf24 100644 --- a/client/poll.go +++ b/client/poll.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/drand/drand-cli/internal/chain" + commonutils "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" @@ -27,7 +27,7 @@ func PollingWatcher(ctx context.Context, c client.Client, chainInfo *chain2.Info defer close(ch) // Initially, wait to synchronize to the round boundary. - _, nextTime := chain.NextRound(time.Now().Unix(), chainInfo.Period, chainInfo.GenesisTime) + _, nextTime := commonutils.NextRound(time.Now().Unix(), chainInfo.Period, chainInfo.GenesisTime) select { case <-ctx.Done(): return diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 6a2bca8..3e6aa13 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -2,70 +2,16 @@ package mock import ( "context" - "net" - "net/http" - "testing" - "time" - clock "github.com/jonboulle/clockwork" + "testing" - "github.com/drand/drand-cli/internal/core" - dhttp "github.com/drand/drand-cli/internal/http" - "github.com/drand/drand-cli/internal/test/mock" - "github.com/drand/drand-cli/internal/test/testlogger" chainCommon "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/log" "github.com/drand/drand/crypto" - "github.com/drand/drand/protobuf/drand" ) // NewMockHTTPPublicServer creates a mock drand HTTP server for testing. func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chainCommon.Info, context.CancelFunc, func(bool)) { t.Helper() - ctx := context.Background() - - server := mock.NewMockServer(t, badSecondRound, sch, clk) - client := core.Proxy(server) - - lg := testlogger.New(t) - lctx := log.ToContext(context.Background(), lg) - ctx, cancel := context.WithCancel(lctx) - - handler, err := dhttp.New(ctx, "") - if err != nil { - t.Fatal(err) - } - - var chainInfo *chainCommon.Info - for i := 0; i < 3; i++ { - protoInfo, err := server.ChainInfo(ctx, &drand.ChainInfoRequest{}) - if err != nil { - time.Sleep(10 * time.Millisecond) - continue - } - chainInfo, err = chainCommon.InfoFromProto(protoInfo) - if err != nil { - time.Sleep(10 * time.Millisecond) - continue - } - break - } - if chainInfo == nil { - t.Fatal("could not use server after 3 attempts.") - } - - handler.RegisterNewBeaconHandler(client, chainInfo.HashString()) - - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - - httpServer := http.Server{Handler: handler.GetHTTPHandler(), ReadHeaderTimeout: 3 * time.Second} - go httpServer.Serve(listener) - - return listener.Addr().String(), chainInfo, func() { - httpServer.Shutdown(ctx) - cancel() - }, server.(mock.Service).EmitRand + //ctx := context.Background() + panic("non-implemented") } diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index c73bf21..0105e0e 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -34,23 +34,23 @@ type Result struct { PSig []byte } -// Randomness is a hash of the signature. -func (r *Result) Randomness() []byte { +// GetRandomness is a hash of the signature. +func (r *Result) GetRandomness() []byte { return r.Rand } -// Signature is the signature of the randomness for this round. -func (r *Result) Signature() []byte { +// GetSignature is the signature of the randomness for this round. +func (r *Result) GetSignature() []byte { return r.Sig } -// PreviousSignature is the signature of the previous round. -func (r *Result) PreviousSignature() []byte { +// GetPreviousSignature is the signature of the previous round. +func (r *Result) GetPreviousSignature() []byte { return r.PSig } -// Round is the round number for this random data. -func (r *Result) Round() uint64 { +// GetRound is the round number for this random data. +func (r *Result) GetRound() uint64 { return r.Rnd } diff --git a/client/utils_test.go b/client/utils_test.go index 9cdffcd..c0dcebc 100644 --- a/client/utils_test.go +++ b/client/utils_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/drand/drand-cli/internal/test" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" + "github.com/drand/drand/common/key" "github.com/drand/drand/crypto" ) @@ -19,11 +19,14 @@ func fakeChainInfo(t *testing.T) *chain.Info { t.Helper() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) + pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) + require.NoError(t, err) + return &chain.Info{ - Scheme: sch.Name, Period: time.Second, GenesisTime: time.Now().Unix(), - PublicKey: test.GenerateIDs(1)[0].Public.Key, + PublicKey: pair.Public.Key, + Scheme: sch.Name, } } @@ -56,10 +59,10 @@ func nextResult(t *testing.T, ch <-chan client.Result) client.Result { func compareResults(t *testing.T, a, b client.Result) { t.Helper() - if a.Round() != b.Round() { - t.Fatal("unexpected result round", a.Round(), b.Round()) + if a.GetRound() != b.GetRound() { + t.Fatal("unexpected result round", a.GetRound(), b.GetRound()) } - if !bytes.Equal(a.Randomness(), b.Randomness()) { - t.Fatal("unexpected result randomness", a.Randomness(), b.Randomness()) + if !bytes.Equal(a.GetRandomness(), b.GetRandomness()) { + t.Fatal("unexpected result randomness", a.GetRandomness(), b.GetRandomness()) } } diff --git a/client/verify.go b/client/verify.go index c1ea62f..017dac8 100644 --- a/client/verify.go +++ b/client/verify.go @@ -78,7 +78,7 @@ func (v *verifyingClient) Watch(ctx context.Context) <-chan client.Result { defer close(outCh) for r := range inCh { if err := v.verify(ctx, info, asRandomData(r)); err != nil { - v.log.Warnw("", "verifying_client", "skipping invalid watch round", "round", r.Round(), "err", err) + v.log.Warnw("", "verifying_client", "skipping invalid watch round", "round", r.GetRound(), "err", err) continue } outCh <- r @@ -88,7 +88,7 @@ func (v *verifyingClient) Watch(ctx context.Context) <-chan client.Result { } type resultWithPreviousSignature interface { - PreviousSignature() []byte + GetPreviousSignature() []byte } func asRandomData(r client.Result) *RandomData { @@ -97,12 +97,12 @@ func asRandomData(r client.Result) *RandomData { return rd } rd = &RandomData{ - Rnd: r.Round(), - Random: r.Randomness(), - Sig: r.Signature(), + Rnd: r.GetRound(), + Random: r.GetRandomness(), + Sig: r.GetSignature(), } if rp, ok := r.(resultWithPreviousSignature); ok { - rd.PreviousSignature = rp.PreviousSignature() + rd.PreviousSignature = rp.GetPreviousSignature() } return rd @@ -123,7 +123,7 @@ func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round var trustPrevSig []byte v.potLk.Lock() - if v.pointOfTrust == nil || v.pointOfTrust.Round() > round { + if v.pointOfTrust == nil || v.pointOfTrust.GetRound() > round { // slow path v.potLk.Unlock() trustPrevSig, err = v.getTrustedPreviousSignature(ctx, 1) @@ -131,8 +131,8 @@ func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round return nil, err } } else { - trustRound = v.pointOfTrust.Round() - trustPrevSig = v.pointOfTrust.Signature() + trustRound = v.pointOfTrust.GetRound() + trustPrevSig = v.pointOfTrust.GetSignature() v.potLk.Unlock() } initialTrustRound := trustRound @@ -148,7 +148,7 @@ func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round b := &common.Beacon{ PreviousSig: trustPrevSig, Round: trustRound, - Signature: next.Signature(), + Signature: next.GetSignature(), } ipk := info.PublicKey.Clone() @@ -158,7 +158,7 @@ func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round v.log.Warnw("", "verifying_client", "failed to verify value", "b", b, "err", err) return []byte{}, fmt.Errorf("verifying beacon: %w", err) } - trustPrevSig = next.Signature() + trustPrevSig = next.GetSignature() } if trustRound == round-1 && trustRound > initialTrustRound { v.potLk.Lock() @@ -177,7 +177,7 @@ func (v *verifyingClient) verify(ctx context.Context, info *chain2.Info, r *Rand ps := r.PreviousSignature if fetchPrevSignature { - ps, err = v.getTrustedPreviousSignature(ctx, r.Round()) + ps, err = v.getTrustedPreviousSignature(ctx, r.GetRound()) if err != nil { return } @@ -185,8 +185,8 @@ func (v *verifyingClient) verify(ctx context.Context, info *chain2.Info, r *Rand b := &common.Beacon{ PreviousSig: ps, // for unchained schemes, this is not used in the VerifyBeacon function and can be nil - Round: r.Round(), - Signature: r.Signature(), + Round: r.GetRound(), + Signature: r.GetSignature(), } ipk := info.PublicKey.Clone() diff --git a/client/verify_test.go b/client/verify_test.go index 624039b..da0701e 100644 --- a/client/verify_test.go +++ b/client/verify_test.go @@ -7,12 +7,12 @@ import ( "github.com/stretchr/testify/require" - "github.com/drand/drand-cli/internal/test/testlogger" - client2 "github.com/drand/drand/client" - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/client/test/result/mock" + client2 "github.com/drand/drand-cli/client" + clientMock "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" "github.com/drand/drand/common/log" + "github.com/drand/drand/common/testlogger" "github.com/drand/drand/crypto" ) @@ -52,10 +52,10 @@ func VerifyFuncTest(t *testing.T, clients, upTo int) { l := testlogger.New(t) c, results := mockClientWithVerifiableResults(ctx, t, l, clients) - res, err := c.Get(context.Background(), results[upTo].Round()) + res, err := c.Get(context.Background(), results[upTo].GetRound()) require.NoError(t, err) - if res.Round() != results[upTo].Round() { - t.Fatal("expected to get result.", results[upTo].Round(), res.Round(), fmt.Sprintf("%v", c)) + if res.GetRound() != results[upTo].GetRound() { + t.Fatal("expected to get result.", results[upTo].GetRound(), res.GetRound(), fmt.Sprintf("%v", c)) } } diff --git a/client/watcher_test.go b/client/watcher_test.go index bf7a629..50be389 100644 --- a/client/watcher_test.go +++ b/client/watcher_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - clientMock "github.com/drand/drand/client/mock" - "github.com/drand/drand/client/test/result/mock" + clientMock "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" ) diff --git a/cmd/Dockerfile b/cmd/Dockerfile deleted file mode 100644 index 2258bbc..0000000 --- a/cmd/Dockerfile +++ /dev/null @@ -1,71 +0,0 @@ -# build this dockerfile with context pointed at the root of the drand repo -FROM --platform=linux/amd64 golang:1.20.1-buster AS builder -MAINTAINER Hector Sanjuan - -ARG version=unknown - -ENV GOPATH /go -ENV SRC_PATH $GOPATH/src/github.com/drand/drand/ -ENV GOPROXY https://proxy.golang.org - -ENV SUEXEC_VERSION v0.2 -ENV TINI_VERSION v0.19.0 -RUN set -x \ - && cd /tmp \ - && git clone https://github.com/ncopa/su-exec.git \ - && cd su-exec \ - && git checkout -q $SUEXEC_VERSION \ - && make \ - && cd /tmp \ - && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ - && chmod +x tini - -# Get the TLS CA certificates, they're not provided by busybox. -RUN apt-get update && apt-get install -y ca-certificates - -COPY go.* $SRC_PATH -WORKDIR $SRC_PATH -RUN go mod download - -COPY . $SRC_PATH -RUN set -x && make build-client - -FROM --platform=linux/amd64 busybox:1-glibc -MAINTAINER Hector Sanjuan - -ENV GOPATH /go -ENV SRC_PATH /go/src/github.com/drand/drand -ENV DRAND_CLIENT_HOME /data/drand_client -# client command-line arguments -ENV DRAND_CLIENT_NETWORK "" -ENV DRAND_CLIENT_HASH "" -ENV DRAND_CLIENT_URL "" -ENV DRAND_CLIENT_RELAYS "" -ENV DRAND_CLIENT_PORT "42777" -ENV DRAND_CLIENT_METRICS_ADDRESS "0.0.0.0:32111" -ENV DRAND_CLIENT_METRICS_GATEWAY "" -ENV DRAND_CLIENT_METRICS_ID "" -ENV DRAND_CLIENT_METRICS_PUSH_INTERVAL 10 - -# expose peer host -EXPOSE 42777 - -# expose promethius API -EXPOSE 32111 - -COPY --from=builder $SRC_PATH/drand-client /usr/local/bin/drand-client -COPY --from=builder $SRC_PATH/cmd/client/entrypoint.sh /usr/local/bin/entrypoint.sh -COPY --from=builder /tmp/su-exec/su-exec /sbin/su-exec -COPY --from=builder /tmp/tini /sbin/tini -COPY --from=builder /etc/ssl/certs /etc/ssl/certs - -RUN mkdir -p $DRAND_CLIENT_HOME && \ - addgroup -g 994 drand_client && \ - adduser -D -h $DRAND_CLIENT_HOME -u 996 -G drand_client drand_client && \ - chown drand_client:drand_client $DRAND_CLIENT_HOME - -VOLUME $DRAND_CLIENT_HOME -ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/entrypoint.sh"] - -# Defaults for demo-client go here -CMD ["--watch", "--insecure"] diff --git a/cmd/entrypoint.sh b/cmd/entrypoint.sh deleted file mode 100644 index 7d11aa0..0000000 --- a/cmd/entrypoint.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e -user=drand_client - -if [ -n "$DOCKER_DEBUG" ]; then - set -x -fi - -if [ "$(id -u)" -eq 0 ]; then - echo "Changing user to $user" - # ensure directories are writable - su-exec "$user" test -w "${DRAND_CLIENT_HOME}" || chown -R -- "$user" "${DRAND_CLIENT_HOME}" - exec su-exec "$user" "$0" "$@" -fi - -exec drand-client \ - --url $DRAND_CLIENT_URL \ - --hash $DRAND_CLIENT_HASH \ - --relays $DRAND_CLIENT_RELAYS \ - --network $DRAND_CLIENT_NETWORK \ - --port $DRAND_CLIENT_PORT \ - --client-metrics-address $DRAND_CLIENT_METRICS_ADDRESS \ - --client-metrics-gateway $DRAND_CLIENT_METRICS_GATEWAY \ - --client-metrics-id $DRAND_CLIENT_METRICS_ID \ - --client-metrics-push-interval $DRAND_CLIENT_METRICS_PUSH_INTERVAL \ - $@ diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 1f51568..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,209 +0,0 @@ -package main - -import ( - "context" - "fmt" - "net/http" - "os" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/prometheus/client_golang/prometheus/push" - "github.com/urfave/cli/v2" - - "github.com/drand/drand-cli/internal/lib" - "github.com/drand/drand/client" - "github.com/drand/drand/common" - "github.com/drand/drand/common/log" -) - -// Automatically set through -ldflags -// Example: go install -ldflags "-X main.buildDate=$(date -u +%d/%m/%Y@%H:%M:%S) -X main.gitCommit=$(git rev-parse HEAD)" -var ( - gitCommit = "none" - buildDate = "unknown" -) - -var watchFlag = &cli.BoolFlag{ - Name: "watch", - Usage: "stream new values as they become available", -} - -var roundFlag = &cli.IntFlag{ - Name: "round", - Usage: "request randomness for a specific round", -} - -var verboseFlag = &cli.BoolFlag{ - Name: "verbose", - Usage: "print debug-level log messages", - EnvVars: []string{"DRAND_CLIENT_VERBOSE"}, -} - -// client metric flags - -var clientMetricsAddressFlag = &cli.StringFlag{ - Name: "client-metrics-address", - Usage: "Server address for Prometheus metrics.", - Value: ":8080", - EnvVars: []string{"DRAND_CLIENT_METRICS"}, -} - -var clientMetricsGatewayFlag = &cli.StringFlag{ - Name: "client-metrics-gateway", - Usage: "Push gateway for Prometheus metrics.", - EnvVars: []string{"DRAND_CLIENT_METRICS_GATEWAY"}, -} - -var clientMetricsPushIntervalFlag = &cli.Int64Flag{ - Name: "client-metrics-push-interval", - Usage: "Push interval in seconds for Prometheus gateway.", - EnvVars: []string{"DRAND_CLIENT_METRICS_PUSH_INTERVAL"}, -} - -var clientMetricsIDFlag = &cli.StringFlag{ - Name: "client-metrics-id", - Usage: "Unique identifier for the client instance, used by the metrics system.", - EnvVars: []string{"DRAND_CLIENT_METRICS_ID"}, -} - -func main() { - version := common.GetAppVersion() - - lg := log.New(nil, log.DefaultLevel, false) - - app := cli.NewApp() - app.Name = "drand-client" - app.Version = version.String() - app.Usage = "CDN Drand client for loading randomness from an HTTP endpoint" - app.Flags = lib.ClientFlags - app.Flags = append(app.Flags, - watchFlag, roundFlag, - clientMetricsAddressFlag, clientMetricsGatewayFlag, clientMetricsIDFlag, - clientMetricsPushIntervalFlag, verboseFlag) - app.Action = func(c *cli.Context) error { - var level int - if c.Bool(verboseFlag.Name) { - level = log.DebugLevel - } else { - level = log.InfoLevel - } - - log.ConfigureDefaultLogger(os.Stderr, level, c.Bool(lib.JSONFlag.Name)) - if level != log.DefaultLevel { - lg = log.New(os.Stderr, level, c.Bool(lib.JSONFlag.Name)) - } - c.Context = log.ToContext(c.Context, lg) - - return Client(c) - } - - // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. - app.EnableBashCompletion = true - - cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("drand client %s (date %v, commit %v)\n", version, buildDate, gitCommit) - } - - err := app.Run(os.Args) - if err != nil { - fmt.Printf("an error was found while executing the command. Err: [%s] \n", err) - os.Exit(1) - } -} - -// Client loads randomness from a server -func Client(c *cli.Context) error { - lg := log.FromContextOrDefault(c.Context) - - var opts []client.Option - - if c.IsSet(clientMetricsIDFlag.Name) { - clientID := c.String(clientMetricsIDFlag.Name) - if !c.IsSet(clientMetricsAddressFlag.Name) && !c.IsSet(clientMetricsGatewayFlag.Name) { - return fmt.Errorf("missing prometheus address or push gateway") - } - metricsAddr := c.String(clientMetricsAddressFlag.Name) - metricsGateway := c.String(clientMetricsGatewayFlag.Name) - metricsPushInterval := c.Int64(clientMetricsPushIntervalFlag.Name) - bridge := newPrometheusBridge(lg, metricsAddr, metricsGateway, metricsPushInterval) - bridgeWithID := client.WithPrometheus(prometheus.WrapRegistererWith( - prometheus.Labels{"client_id": clientID}, - bridge)) - opts = append(opts, bridgeWithID) - } - - apiClient, err := lib.Create(c, c.IsSet(clientMetricsIDFlag.Name), opts...) - if err != nil { - return err - } - - if c.IsSet(watchFlag.Name) { - return Watch(apiClient) - } - - round := uint64(0) - if c.IsSet(roundFlag.Name) { - round = uint64(c.Int(roundFlag.Name)) - } - rand, err := apiClient.Get(context.Background(), round) - if err != nil { - return err - } - fmt.Printf("%d\t%x\n", rand.Round(), rand.Randomness()) - return nil -} - -// Watch streams randomness from a client -func Watch(inst client.Watcher) error { - results := inst.Watch(context.Background()) - for r := range results { - fmt.Printf("%d\t%x\n", r.Round(), r.Randomness()) - } - return nil -} - -func newPrometheusBridge(l log.Logger, address, gateway string, pushIntervalSec int64) prometheus.Registerer { - b := &prometheusBridge{ - address: address, - pushIntervalSec: pushIntervalSec, - Registry: prometheus.NewRegistry(), - log: l, - } - if gateway != "" { - b.pusher = push.New(gateway, "drand_client_observations_push").Gatherer(b.Registry) - go b.pushLoop() - } - if address != "" { - http.Handle("/metrics", promhttp.HandlerFor(b.Registry, promhttp.HandlerOpts{ - Timeout: 10 * time.Second, - })) - go func() { - // http.ListenAndServe is marked as problematic - // because it does not have tweaked timeouts out of the box. - - //nolint - err := http.ListenAndServe(address, nil) - l.Fatalw("", "client", err) - }() - } - return b -} - -type prometheusBridge struct { - *prometheus.Registry - address string - pushIntervalSec int64 - pusher *push.Pusher - log log.Logger -} - -func (b *prometheusBridge) pushLoop() { - for { - time.Sleep(time.Second * time.Duration(b.pushIntervalSec)) - if err := b.pusher.Push(); err != nil { - b.log.Infow("", "client_metrics", "prometheus gateway push (%v)", err) - } - } -} diff --git a/go.mod b/go.mod index 675992d..1dc92da 100644 --- a/go.mod +++ b/go.mod @@ -5,15 +5,11 @@ go 1.20 replace github.com/drand/drand => ../drand require ( - github.com/BurntSushi/toml v1.3.2 github.com/drand/drand v0.0.0-00010101000000-000000000000 github.com/drand/kyber v1.2.0 - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 - github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 - github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 github.com/libp2p/go-libp2p v0.30.0 github.com/libp2p/go-libp2p-pubsub v0.9.3 github.com/multiformats/go-multiaddr v0.11.0 @@ -21,18 +17,13 @@ require ( github.com/prometheus/client_golang v1.16.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.25.7 - go.opentelemetry.io/otel v1.17.0 - google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 ) require ( - github.com/ardanlabs/darwin/v2 v2.0.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/briandowns/spinner v1.23.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // 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 github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -40,57 +31,30 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/drand/kyber-bls12381 v0.3.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/fatih/color v1.15.0 // 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/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-chi/chi v1.5.4 // 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.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/gogo/status v1.1.1 // indirect - github.com/golang/glog v1.1.1 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect github.com/huin/goupnp v1.2.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-datastore v0.6.0 // 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/jedib0t/go-pretty/v6 v6.4.7 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect - github.com/lib/pq v1.10.9 // 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 @@ -101,9 +65,7 @@ require ( github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // 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.19 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.55 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect @@ -121,9 +83,6 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect - github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect - github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -135,31 +94,14 @@ require ( github.com/quic-go/quic-go v0.37.6 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect - github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sercand/kuberesolver/v4 v4.0.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect - github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73 // indirect - 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.etcd.io/bbolt v1.3.7 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.17.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect + go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect golang.org/x/crypto v0.12.0 // indirect @@ -168,12 +110,10 @@ require ( golang.org/x/net v0.14.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect - google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/grpc v1.57.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index 1874fcf..ee2248c 100644 --- a/go.sum +++ b/go.sum @@ -2,477 +2,37 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT 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= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -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.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -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/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -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/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -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.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -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/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -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/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -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/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -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.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -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/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -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.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -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/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -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/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -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/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -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/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -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.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -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/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -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= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= -github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfKxvSy1HMhoes= -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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= -github.com/briandowns/spinner v1.23.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.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -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/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/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= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -485,16 +45,6 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -503,299 +53,111 @@ github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xt github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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/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/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= 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/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -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.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/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-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-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= -github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= -github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= -github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= -github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -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= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -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= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -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/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 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.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= -github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= github.com/hashicorp/golang-lru/v2 v2.0.5/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.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -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= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= -github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= -github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg= -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/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= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE= -github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= -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.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/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= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M= -github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -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.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -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= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -820,30 +182,15 @@ github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8S github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -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/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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -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.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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -858,13 +205,8 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8Rv github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -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/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/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= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -892,8 +234,6 @@ github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqd 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= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nikkolasg/hexjson v0.1.0 h1:Cgi1MSZVQFoJKYeRpBNEcdF3LB+Zo4fYKsDz7h8uJYQ= @@ -904,63 +244,25 @@ github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= -github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -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= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= @@ -972,19 +274,11 @@ github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2Ep github.com/quic-go/webtransport-go v0.5.3/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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -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.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sercand/kuberesolver/v4 v4.0.0 h1:frL7laPDG/lFm5n98ODmWnn+cvPpzlkf3LhzuPhcHP4= -github.com/sercand/kuberesolver/v4 v4.0.0/go.mod h1:F4RGyuRmMAjeXHKL+w4P7AwUnPceEAPAhxUgXZjKgvM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -1009,191 +303,83 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= 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/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= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -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= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -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/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= 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-20230531151736-e2613bee6b73 h1:CMM9+/AgM77vaMXMQedzqPRMuNwjbI0EcdofPqxc9F8= -github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73/go.mod h1:rgbeLfJUtEr+G74cwFPR1k/4N0kDeaeSv/qhUNE4hm8= -github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= -github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= -go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= -go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -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.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= -go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.20.0 h1:BLOA1cZBAGSbRiNuGCCKiFrCdYB7deeHDeD1SueyOfA= -go.opentelemetry.io/proto/otlp v0.20.0/go.mod h1:3QgjzPALBIv9pcknj2EXGPXjYPFdUh/RQfF8Lz3+Vnw= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/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-20211108221036-ceb1ce70b4fa/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.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= -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= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1201,93 +387,23 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 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-20210813160813-60bc85c4be6d/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= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -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.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= 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= @@ -1295,140 +411,39 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-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= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -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/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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= @@ -1436,342 +451,52 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -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= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -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/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/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -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= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -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-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-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs= -google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk= -google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 h1:DEH99RbiLZhMxrpEJCZ0A+wdTe0EOgou/poSLx9vWf4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= +google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -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.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -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/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1780,15 +505,7 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd 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= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/internal/cli.go b/internal/cli.go index f298173..f8e12b4 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -1,36 +1,12 @@ -// Package drand is a distributed randomness beacon. It provides periodically an -// unpredictable, bias-resistant, and verifiable random value. package drand import ( - "bufio" - "bytes" - "context" - "errors" "fmt" - "io" - "os" - "path" - "path/filepath" - "regexp" - "runtime" - "strconv" - "strings" "sync" - "github.com/BurntSushi/toml" "github.com/urfave/cli/v2" - "github.com/drand/drand-cli/internal/core" - "github.com/drand/drand-cli/internal/core/migration" - "github.com/drand/drand-cli/internal/fs" - "github.com/drand/drand-cli/internal/net" "github.com/drand/drand/common" - "github.com/drand/drand/common/key" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" - common2 "github.com/drand/drand/protobuf/common" - "github.com/drand/drand/protobuf/drand" ) // Automatically set through -ldflags @@ -42,13 +18,6 @@ var ( var SetVersionPrinter sync.Once -const defaultPort = "8080" - -func banner(w io.Writer) { - version := common.GetAppVersion() - _, _ = fmt.Fprintf(w, "drand %s (date %v, commit %v)\n", version.String(), buildDate, gitCommit) -} - var verboseFlag = &cli.BoolFlag{ Name: "verbose", Usage: "If set, verbosity is at the debug level", @@ -89,25 +58,11 @@ var jsonFlag = &cli.BoolFlag{ var beaconIDFlag = &cli.StringFlag{ Name: "id", - Usage: "Indicates the id for the randomness generation process which will be started", + Usage: "Indicates the id of the beacon chain you're interested in", Value: "", EnvVars: []string{"DRAND_ID"}, } -var listIdsFlag = &cli.BoolFlag{ - Name: "list-ids", - Usage: "Indicates if it only have to list the running beacon ids instead of the statuses.", - Value: false, - EnvVars: []string{"DRAND_LIST_IDS"}, -} - -var allBeaconsFlag = &cli.BoolFlag{ - Name: "all", - Usage: "Indicates if we have to interact with all beacons chains", - Value: false, - EnvVars: []string{"DRAND_ALL"}, -} - var appCommands = []*cli.Command{ { Name: "get", @@ -123,38 +78,15 @@ var appCommands = []*cli.Command{ "beacon via TLS and falls back to plaintext communication " + "if the contacted node has not activated TLS in which case " + "it prints a warning.\n", - Flags: toArray(roundFlag, nodeFlag), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("getPublicRandomness") - return getPublicRandomness(c, l) - }, + Flags: toArray(roundFlag, nodeFlag), + Action: getPublicRandomness, }, { Name: "chain-info", Usage: "Get the binding chain information that this node participates to", ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.", Flags: toArray(hashOnly, hashInfoNoReq), - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("getChainInfo") - return getChainInfo(c, l) - }, - }, - }, - }, - { - Name: "util", - Usage: "Multiple commands of utility functions, such as reseting a state, checking the connection of a peer...", - Subcommands: []*cli.Command{ - { - Name: "list-schemes", - Usage: "List all scheme ids available to use\n", - Action: func(c *cli.Context) error { - l := log.New(nil, logLevel(c), logJSON(c)). - Named("schemesCmd") - return schemesCmd(c, l) - }, + Action: getChainInfo, }, }, }, @@ -195,253 +127,27 @@ func CLI() *cli.App { app.Commands = appComm // we need to copy the underlying flags to avoid races verbFlag := *verboseFlag - foldFlag := *folderFlag - app.Flags = toArray(&verbFlag, &foldFlag) - app.Before = testWindows + app.Flags = toArray(&verbFlag) return app } -func resetCmd(c *cli.Context, l log.Logger) error { - conf := contextToConfig(c, l) - - fmt.Fprintf(c.App.Writer, "You are about to delete your local share, group file and generated random beacons. "+ - "Are you sure you wish to perform this operation? [y/N]") - reader := bufio.NewReader(c.App.Reader) - - answer, err := reader.ReadString('\n') - if err != nil { - return fmt.Errorf("error reading: %w", err) - } - - answer = strings.ToLower(strings.TrimSpace(answer)) - if answer != "y" { - fmt.Fprintf(c.App.Writer, "drand: not reseting the state.") - return nil - } - - stores, err := getKeyStores(c, l) - if err != nil { - fmt.Fprintf(c.App.Writer, "drand: err reading beacons database: %v\n", err) - os.Exit(1) - } - - for beaconID, store := range stores { - if err := store.Reset(); err != nil { - fmt.Fprintf(c.App.Writer, "drand: beacon id [%s] - err reseting key store: %v\n", beaconID, err) - os.Exit(1) - } - - if err := os.RemoveAll(path.Join(conf.ConfigFolderMB(), beaconID)); err != nil { - fmt.Fprintf(c.App.Writer, "drand: beacon id [%s] - err reseting beacons database: %v\n", beaconID, err) - os.Exit(1) - } - - fmt.Printf("drand: beacon id [%s] - database reset\n", beaconID) - } - - return nil -} - -func askPort(c *cli.Context) string { - for { - fmt.Fprintf(c.App.Writer, "No valid port given. Please, choose a port number (or ENTER for default port 8080): ") - - reader := bufio.NewReader(c.App.Reader) - input, err := reader.ReadString('\n') - if err != nil { - continue - } - - portStr := strings.TrimSpace(input) - if portStr == "" { - fmt.Fprintln(c.App.Writer, "Default port selected") - return defaultPort - } - - port, err := strconv.Atoi(portStr) - if err != nil || port < 1000 || port > 65536 { - continue - } - - return portStr - } -} - -func runMigration(c *cli.Context, l log.Logger) error { - if err := checkArgs(c); err != nil { - return err - } - - config := contextToConfig(c, l) - - return migration.MigrateSBFolderStructure(config.ConfigFolder()) -} - -func checkMigration(c *cli.Context, l log.Logger) error { - if err := checkArgs(c); err != nil { - return err - } - - config := contextToConfig(c, l) - - if isPresent := migration.CheckSBFolderStructure(config.ConfigFolder()); isPresent { - return fmt.Errorf("single-beacon drand folder structure was not migrated, " + - "please first do it with 'drand util migrate' command") - } - - if fs.CreateSecureFolder(config.ConfigFolderMB()) == "" { - return fmt.Errorf("something went wrong with the multi beacon folder. " + - "Make sure that you have the appropriate rights") - } - - return nil +func isVerbose(c *cli.Context) bool { + return c.IsSet(verboseFlag.Name) } -func testWindows(c *cli.Context) error { - // x509 not available on windows: must run without TLS - if runtime.GOOS == "windows" && !c.Bool(insecureFlag.Name) { - return errors.New("TLS is not available on Windows, please disable TLS") - } - return nil +func toArray(flags ...cli.Flag) []cli.Flag { + return flags } -func keygenCmd(c *cli.Context, l log.Logger) error { - args := c.Args() - if !args.Present() { - return errors.New("missing drand address in argument. Abort") - } - - if args.Len() > 1 { - return fmt.Errorf("expecting only one argument, the address, but got:"+ - "\n\t%v\nAborting. Note that the flags need to go before the argument", args.Slice()) - } - - addr := args.First() - var validID = regexp.MustCompile(`:\d+$`) - if !validID.MatchString(addr) { - fmt.Println("Invalid port:", addr) - addr = addr + ":" + askPort(c) - } - - sch, err := crypto.SchemeFromName(c.String(schemeFlag.Name)) - if err != nil { - return err - } - - var priv *key.Pair - if c.Bool(insecureFlag.Name) { - fmt.Println("Generating private / public key pair without TLS.") - priv, err = key.NewKeyPair(addr, sch) - } else { - fmt.Println("Generating private / public key pair with TLS indication") - priv, err = key.NewTLSKeyPair(addr, sch) - } - if err != nil { - return err - } - - config := contextToConfig(c, l) - beaconID := getBeaconID(c) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - - if _, err := fileStore.LoadKeyPair(sch); err == nil { - keyDirectory := path.Join(config.ConfigFolderMB(), beaconID) - fmt.Fprintf(c.App.Writer, "Keypair already present in `%s`.\nRemove them before generating new one\n", keyDirectory) - return nil - } - if err := fileStore.SaveKeyPair(priv); err != nil { - return fmt.Errorf("could not save key: %w", err) - } - - fullpath := path.Join(config.ConfigFolderMB(), beaconID, key.FolderName) - absPath, err := filepath.Abs(fullpath) - - if err != nil { - return fmt.Errorf("err getting full path: %w", err) - } - fmt.Println("Generated keys at ", absPath) - - var buff bytes.Buffer - if err := toml.NewEncoder(&buff).Encode(priv.Public.TOML()); err != nil { - return err - } - - buff.WriteString("\n") - fmt.Println(buff.String()) +// TODO +func getPublicRandomness(c *cli.Context) error { return nil } -func groupOut(c *cli.Context, group *key.Group) error { - if c.IsSet("out") { - groupPath := c.String("out") - if err := key.Save(groupPath, group, false); err != nil { - return fmt.Errorf("drand: can't save group to specified file name: %w", err) - } - } else if c.Bool(hashOnly.Name) { - fmt.Fprintf(c.App.Writer, "%x\n", group.Hash()) - } else { - var buff bytes.Buffer - if err := toml.NewEncoder(&buff).Encode(group.TOML()); err != nil { - return fmt.Errorf("drand: can't encode group to TOML: %w", err) - } - buff.WriteString("\n") - fmt.Fprintf(c.App.Writer, "The following group.toml file has been created\n") - fmt.Fprint(c.App.Writer, buff.String()) - fmt.Fprintf(c.App.Writer, "\nHash of the group configuration: %x\n", group.Hash()) - } +func getChainInfo(c *cli.Context) error { return nil } -func checkIdentityAddress(lg log.Logger, conf *core.Config, addr string, tls bool, beaconID string) error { - peer := net.CreatePeer(addr, tls) - client := net.NewGrpcClientFromCertManager(lg, conf.Certs()) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - metadata := &common2.Metadata{BeaconID: beaconID} - identityResp, err := client.GetIdentity(ctx, peer, &drand.IdentityRequest{Metadata: metadata}) - if err != nil { - return err - } - - identity := &drand.Identity{ - Signature: identityResp.Signature, - Tls: identityResp.Tls, - Address: identityResp.Address, - Key: identityResp.Key, - } - sch, err := crypto.SchemeFromName(identityResp.SchemeName) - if err != nil { - lg.Errorw("received an invalid SchemeName in identity response", "received", identityResp.SchemeName) - return err - } - id, err := key.IdentityFromProto(identity, sch) - if err != nil { - return err - } - if id.Address() != addr { - return fmt.Errorf("mismatch of address: contact %s reply with %s", addr, id.Address()) - } +func schemesCmd(c *cli.Context) error { return nil } - -func isVerbose(c *cli.Context) bool { - return c.IsSet(verboseFlag.Name) -} - -func logLevel(c *cli.Context) int { - if isVerbose(c) { - return log.DebugLevel - } - - return log.ErrorLevel -} - -func logJSON(c *cli.Context) bool { - return c.Bool(jsonFlag.Name) -} - -func toArray(flags ...cli.Flag) []cli.Flag { - return flags -} diff --git a/internal/cli_test.go b/internal/cli_test.go index 9f0bfc6..7b6dc97 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -1,1520 +1,1520 @@ package drand -import ( - "bytes" - "context" - "encoding/hex" - "errors" - "fmt" - gnet "net" - "os" - "os/exec" - "path" - "path/filepath" - "strconv" - "strings" - "testing" - "time" - - "github.com/BurntSushi/toml" - "github.com/kabukky/httpscerts" - json "github.com/nikkolasg/hexjson" - "github.com/stretchr/testify/require" - - "github.com/drand/drand-cli/internal/chain" - "github.com/drand/drand-cli/internal/chain/boltdb" - "github.com/drand/drand-cli/internal/core" - dkg2 "github.com/drand/drand-cli/internal/dkg" - "github.com/drand/drand-cli/internal/fs" - "github.com/drand/drand-cli/internal/net" - "github.com/drand/drand-cli/internal/test" - "github.com/drand/drand-cli/internal/test/testlogger" - "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/key" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" - "github.com/drand/kyber" - "github.com/drand/kyber/share" - "github.com/drand/kyber/share/dkg" - "github.com/drand/kyber/util/random" -) - -func TestMigrate(t *testing.T) { - tmp := getSBFolderStructure(t) - - args := []string{"drand", "util", "migrate", "--folder", tmp} - app := CLI() - require.NoError(t, app.Run(args)) - - l := testlogger.New(t) - config := core.NewConfig(l, core.WithConfigFolder(tmp)) - defaultBeaconPath := path.Join(config.ConfigFolderMB(), common.DefaultBeaconID) - - newGroupFilePath := path.Join(defaultBeaconPath, key.GroupFolderName) - newKeyFilePath := path.Join(defaultBeaconPath, key.FolderName) - newDBFilePath := path.Join(defaultBeaconPath, core.DefaultDBFolder) - - if !fs.FolderExists(defaultBeaconPath, newGroupFilePath) { - t.Errorf("group folder should have been migrated") - } - if !fs.FolderExists(defaultBeaconPath, newKeyFilePath) { - t.Errorf("key folder should have been migrated") - } - if !fs.FolderExists(defaultBeaconPath, newDBFilePath) { - t.Errorf("db folder should have been migrated") - } -} - -func TestResetError(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := getSBFolderStructure(t) - - args := []string{"drand", "util", "reset", "--folder", tmp, "--id", beaconID} - app := CLI() - require.Error(t, app.Run(args)) -} - -func TestDeleteBeaconError(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := getSBFolderStructure(t) - - // that command should delete round 3 and 4 - args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} - app := CLI() - require.Error(t, app.Run(args)) -} - -func TestDeleteBeacon(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - l := testlogger.New(t) - ctx := context.Background() - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - if sch.Name == crypto.DefaultSchemeID { - ctx = chain.SetPreviousRequiredOnContext(ctx) - } - tmp := path.Join(t.TempDir(), "drand") - - opt := core.WithConfigFolder(tmp) - conf := core.NewConfig(l, opt) - fs.CreateSecureFolder(conf.DBFolder(beaconID)) - store, err := boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) - require.NoError(t, err) - err = store.Put(ctx, &common.Beacon{ - Round: 1, - Signature: []byte("Hello"), - }) - require.NoError(t, err) - err = store.Put(ctx, &common.Beacon{ - Round: 2, - Signature: []byte("Hello"), - }) - require.NoError(t, err) - err = store.Put(ctx, &common.Beacon{ - Round: 3, - Signature: []byte("Hello"), - }) - require.NoError(t, err) - err = store.Put(ctx, &common.Beacon{ - Round: 4, - Signature: []byte("hello"), - }) - require.NoError(t, err) - // try to fetch round 3 and 4 - b, err := store.Get(ctx, 3) - require.NoError(t, err) - require.NotNil(t, b) - b, err = store.Get(ctx, 4) - require.NoError(t, err) - require.NotNil(t, b) - - err = store.Close() - require.NoError(t, err) - - args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} - app := CLI() - require.NoError(t, app.Run(args)) - - store, err = boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) - require.NoError(t, err) - - // try to fetch round 3 and 4 - it should now fail - _, err = store.Get(ctx, 3) - require.Error(t, err) - - _, err = store.Get(ctx, 4) - require.Error(t, err) -} - -func TestKeySelfSignError(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := getSBFolderStructure(t) - - args := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} - app := CLI() - require.Error(t, app.Run(args)) -} - -func TestKeySelfSign(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - l := testlogger.New(t) - - tmp := path.Join(t.TempDir(), "drand") - - args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} - require.NoError(t, CLI().Run(args)) - - selfSign := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} - // try self sign, it should only print that it's already the case - expectedOutput := "already self signed" - testCommand(t, selfSign, expectedOutput) - - // load, remove signature and save - config := core.NewConfig(l, core.WithConfigFolder(tmp)) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - - pair, err := fileStore.LoadKeyPair(nil) - require.NoError(t, err) - pair.Public.Signature = nil - require.NoError(t, fileStore.SaveKeyPair(pair)) - - expectedOutput = "identity self signed" - testCommand(t, selfSign, expectedOutput) -} - -func TestKeyGenError(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := getSBFolderStructure(t) - - args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} - app := CLI() - require.Error(t, app.Run(args)) -} - -func TestKeyGen(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - l := testlogger.New(t) - - tmp := path.Join(t.TempDir(), "drand") - sch, _ := crypto.GetSchemeFromEnv() - args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "--scheme", sch.Name, "127.0.0.1:8081"} - require.NoError(t, CLI().Run(args)) - - config := core.NewConfig(l, core.WithConfigFolder(tmp)) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - priv, err := fileStore.LoadKeyPair(nil) - require.NoError(t, err) - require.NotNil(t, priv.Public) - - tmp2 := path.Join(t.TempDir(), "drand2") - - args = []string{"drand", "generate-keypair", "--folder", tmp2, "--id", beaconID, "--scheme", sch.Name} - require.Error(t, CLI().Run(args)) - - config = core.NewConfig(l, core.WithConfigFolder(tmp2)) - fileStore = key.NewFileStore(config.ConfigFolderMB(), beaconID) - priv, err = fileStore.LoadKeyPair(nil) - require.Error(t, err) - require.Nil(t, priv) -} - -// tests valid commands and then invalid commands -func TestStartAndStop(t *testing.T) { - tmpPath := t.TempDir() - - n := 5 - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - _, group := test.BatchIdentities(n, sch, beaconID) - groupPath := path.Join(tmpPath, "group.toml") - require.NoError(t, key.Save(groupPath, group, false)) - - privateAddr := test.Addresses(1)[0] - - args := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmpPath, "--id", beaconID, privateAddr} - require.NoError(t, CLI().Run(args)) - - startCh := make(chan bool) - go func() { - startArgs := []string{"drand", "start", "--tls-disable", "--folder", tmpPath, "--private-listen", privateAddr} - // Allow the rest of the test to start - // Any error will be caught in the error check below - startCh <- true - err := CLI().Run(startArgs) - if err != nil { - t.Errorf("error starting the node %s\n", err) - t.Fail() - return - } - // After we finish the execution, flag that we finished. - // This allows the test to exit cleanly without reaching the - // timeout at the end. - startCh <- true - // TODO : figuring out how to not panic in grpc call - // ERROR: 2020/01/23 21:06:28 grpc: server failed to encode response: - // rpc error: code = Internal desc = grpc: error while marshaling: proto: - // Marshal called with nil - }() - <-startCh - time.Sleep(200 * time.Millisecond) - - stopArgs := []string{"drand", "stop"} - err = CLI().Run(stopArgs) - require.NoError(t, err) - - select { - case <-startCh: - case <-time.After(1 * time.Second): - t.Fatal("drand daemon did not stop") - } -} - -func TestUtilCheckReturnsErrorForPortNotMatchingKeypair(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - beaconID := test.GetBeaconIDFromEnv() - - tmp := t.TempDir() - - // try to generate a keypair and make it listen on another address - keyPort := test.FreePort() - keyAddr := "127.0.0.1:" + keyPort - generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} - require.NoError(t, CLI().Run(generate)) - - listenPort := test.FreePort() - listenAddr := "127.0.0.1:" + listenPort - listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", listenAddr, "--folder", tmp} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - waitCh := make(chan bool) - go func() { - waitCh <- true - err := CLI().RunContext(ctx, listen) - if err != nil { - t.Errorf("error while starting the node %v\n", err) - t.Fail() - return - } - }() - <-waitCh - // TODO can we maybe try to bind continuously to not having to wait - time.Sleep(200 * time.Millisecond) - - // run the check tool it should fail because key and address are not - // consistent - check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, listenAddr} - require.Error(t, CLI().Run(check)) -} - -func TestUtilCheckSucceedsForPortMatchingKeypair(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := t.TempDir() - - keyPort := test.FreePort() - keyAddr := "127.0.0.1:" + keyPort - generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} - require.NoError(t, CLI().Run(generate)) - - listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", keyAddr, "--folder", tmp} - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - waitCh := make(chan bool) - go func() { - waitCh <- true - err := CLI().RunContext(ctx, listen) - if err != nil { - t.Errorf("error while starting the node %v\n", err) - t.Fail() - return - } - }() - <-waitCh - // TODO can we maybe try to bind continuously to not having to wait - time.Sleep(200 * time.Millisecond) - - check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, keyAddr} - require.NoError(t, CLI().Run(check)) -} - -//nolint:funlen -func TestStartWithoutGroup(t *testing.T) { - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - tmpPath := path.Join(t.TempDir(), "drand") - require.NoError(t, os.Mkdir(tmpPath, 0o740)) - - pubPath := path.Join(tmpPath, "pub.key") - port1, _ := strconv.Atoi(test.FreePort()) - addr := "127.0.0.1:" + strconv.Itoa(port1) - - ctrlPort1, ctrlPort2, metricsPort := test.FreePort(), test.FreePort(), test.FreePort() - - priv, err := key.NewKeyPair(addr, sch) - require.NoError(t, err) - require.NoError(t, key.Save(pubPath, priv.Public, false)) - - config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - require.NoError(t, fileStore.SaveKeyPair(priv)) - - startArgs := []string{ - "drand", - "start", - "--private-listen", priv.Public.Address(), - "--tls-disable", - "--verbose", - "--folder", tmpPath, - "--control", ctrlPort1, - "--metrics", "127.0.0.1:" + metricsPort, - } - - go func() { - err := CLI().Run(startArgs) - if err != nil { - t.Errorf(err.Error()) - } - }() - - time.Sleep(500 * time.Millisecond) - - t.Log("--- DRAND SHARE --- (expected to fail)") - // this must fail because not enough arguments - // TODO - test vectors testing on the inputs - - initDKGArgs := []string{"drand", "share", "--control", ctrlPort1, "--id", beaconID} - require.Error(t, CLI().Run(initDKGArgs)) - - t.Log("--- DRAND STOP --- (failing instance)") - err = CLI().Run([]string{"drand", "stop", "--control", ctrlPort1}) - require.NoError(t, err) - - t.Log(" --- DRAND GROUP ---") - - // fake group - _, group := test.BatchIdentities(5, sch, beaconID) - - // fake dkg output - fakeKey := sch.KeyGroup.Point().Pick(random.New()) - distKey := &key.DistPublic{ - Coefficients: []kyber.Point{ - fakeKey, - sch.KeyGroup.Point().Pick(random.New()), - sch.KeyGroup.Point().Pick(random.New()), - }, - } - priv.Public.TLS = false - - group.Period = 5 * time.Second - group.GenesisTime = time.Now().Unix() - 10 - group.PublicKey = distKey - group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} - group.Nodes[1] = &key.Node{Identity: priv.Public, Index: 1} - groupPath := path.Join(tmpPath, "drand_group.toml") - require.NoError(t, key.Save(groupPath, group, false)) - - // save it also to somewhere drand will find it - require.NoError(t, fileStore.SaveGroup(group)) - - // fake share - scalarOne := sch.KeyGroup.Scalar().One() - s := &share.PriShare{I: 2, V: scalarOne} - fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} - require.NoError(t, fileStore.SaveShare(fakeShare)) - - // save a fake complete DKG in the store - dStore, err := dkg2.NewDKGStore(tmpPath, nil) - require.NoError(t, err) - err = dStore.SaveFinished(beaconID, &dkg2.DBState{ - BeaconID: beaconID, - Epoch: 1, - State: dkg2.Complete, - Threshold: 1, - Timeout: time.Unix(2549084715, 0).UTC(), // this will need updated in 2050 :^) - SchemeID: sch.Name, - GenesisTime: time.Unix(1669718523, 0).UTC(), - GenesisSeed: []byte("deadbeef"), - TransitionTime: time.Unix(1669718523, 0).UTC(), - CatchupPeriod: 5 * time.Second, - BeaconPeriod: 10 * time.Second, - - Leader: nil, - Remaining: nil, - Joining: nil, - Leaving: nil, - - Acceptors: nil, - Rejectors: nil, - - FinalGroup: group, - KeyShare: fakeShare, - }) - require.NoError(t, err) - - // Have to close it afterwards or starting the node will become unresponsive - err = dStore.Close() - require.NoError(t, err) - - t.Logf(" --- DRAND START --- control %s\n", ctrlPort2) - - start2 := []string{ - "drand", - "start", - "--control", ctrlPort2, - "--private-listen", priv.Public.Address(), - "--tls-disable", - "--folder", tmpPath, - "--verbose", - } - - go func() { - err := CLI().Run(start2) - if err != nil { - t.Errorf("error while starting second node: %v", err) - } - }() - - stop2 := []string{"drand", "stop", "--control", ctrlPort2} - defer func() { - err := CLI().Run(stop2) - if err != nil { - t.Errorf("error while stopping second node: %v", err) - } - }() - - time.Sleep(500 * time.Millisecond) - - testStartedDrandFunctional(t, ctrlPort2, tmpPath, priv.Public.Address(), group, fileStore, beaconID) -} - -func testStartedDrandFunctional(t *testing.T, ctrlPort, rootPath, address string, group *key.Group, fileStore key.Store, beaconID string) { - t.Helper() - lg := testlogger.New(t) - - testPing(t, ctrlPort) - testStatus(t, ctrlPort, beaconID) - testListSchemes(t, ctrlPort) - - require.NoError(t, toml.NewEncoder(os.Stdout).Encode(group.TOML())) - - t.Log("Running CHAIN-INFO command") - chainInfo, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") - require.NoError(t, err) - expectedOutput := string(chainInfo) - chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-disable", address} - testCommand(t, chainInfoCmd, expectedOutput) - - t.Log("Running CHAIN-INFO --HASH command") - chainInfoCmdHash := []string{"drand", "get", "chain-info", "--hash", "--tls-disable", address} - expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) - testCommand(t, chainInfoCmdHash, expectedOutput) - - showChainInfo := []string{"drand", "show", "chain-info", "--control", ctrlPort} - buffCi, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") - require.NoError(t, err) - testCommand(t, showChainInfo, string(buffCi)) - - showChainInfo = []string{"drand", "show", "chain-info", "--hash", "--control", ctrlPort} - expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) - testCommand(t, showChainInfo, expectedOutput) - - // reset state - resetCmd := []string{"drand", "util", "reset", "--folder", rootPath, "--id", beaconID} - r, w, err := os.Pipe() - require.NoError(t, err) - _, err = w.WriteString("y\n") - require.NoError(t, err) - os.Stdin = r - require.NoError(t, CLI().Run(resetCmd)) - _, err = fileStore.LoadShare(nil) - require.Error(t, err) - _, err = fileStore.LoadGroup() - require.Error(t, err) -} - -func testPing(t *testing.T, ctrlPort string) { - t.Helper() - - var err error - - t.Logf(" + running PING command with %s\n", ctrlPort) - for i := 0; i < 3; i++ { - ping := []string{"drand", "util", "ping", "--control", ctrlPort} - err = CLI().Run(ping) - if err == nil { - break - } - time.Sleep(500 * time.Millisecond) - } - require.NoError(t, err) -} - -func testStatus(t *testing.T, ctrlPort, beaconID string) { - t.Helper() - - var err error - - t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) - for i := 0; i < 3; i++ { - status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} - err = CLI().Run(status) - if err == nil { - return - } - time.Sleep(500 * time.Millisecond) - } - require.NoError(t, err) -} - -func testFailStatus(t *testing.T, ctrlPort, beaconID string) { - t.Helper() - - var err error - - t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) - for i := 0; i < 3; i++ { - status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} - err = CLI().Run(status) - require.Error(t, err) - time.Sleep(500 * time.Millisecond) - } -} - -func testListSchemes(t *testing.T, ctrlPort string) { - t.Helper() - - var err error - - t.Logf(" + running list schemes command with %s\n", ctrlPort) - for i := 0; i < 3; i++ { - schemes := []string{"drand", "util", "list-schemes", "--control", ctrlPort} - err = CLI().Run(schemes) - if err == nil { - break - } - time.Sleep(500 * time.Millisecond) - } - require.NoError(t, err) -} - -//nolint:funlen //This is a test -func TestClientTLS(t *testing.T) { - t.Skip("The test fails because the logic for generating the group has changed") - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - tmpPath := path.Join(t.TempDir(), "drand") - require.NoError(t, os.Mkdir(tmpPath, 0o740)) - - groupPath := path.Join(tmpPath, "group.toml") - certPath := path.Join(tmpPath, "server.pem") - keyPath := path.Join(tmpPath, "key.pem") - pubPath := path.Join(tmpPath, "pub.key") - - freePort := test.FreePort() - addr := "127.0.0.1:" + freePort - ctrlPort := test.FreePort() - metricsPort := test.FreePort() - - priv, err := key.NewTLSKeyPair(addr, nil) - require.NoError(t, err) - require.NoError(t, key.Save(pubPath, priv.Public, false)) - - config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - err = fileStore.SaveKeyPair(priv) - require.NoError(t, err) - - if httpscerts.Check(certPath, keyPath) != nil { - t.Log("generating on the fly") - h, _, err := gnet.SplitHostPort(priv.Public.Address()) - require.NoError(t, err) - err = httpscerts.Generate(certPath, keyPath, h) - require.NoError(t, err) - } - - // fake group - _, group := test.BatchTLSIdentities(5, sch, beaconID) - // fake dkg outuput - fakeKey := sch.KeyGroup.Point().Pick(random.New()) - // need a threshold of coefficients - distKey := &key.DistPublic{ - Coefficients: []kyber.Point{ - fakeKey, - sch.KeyGroup.Point().Pick(random.New()), - sch.KeyGroup.Point().Pick(random.New()), - }, - } - group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} - group.Period = 2 * time.Minute - group.GenesisTime = time.Now().Unix() - group.PublicKey = distKey - require.NoError(t, fileStore.SaveGroup(group)) - require.NoError(t, key.Save(groupPath, group, false)) - - // fake share - scalarOne := sch.KeyGroup.Scalar().One() - s := &share.PriShare{I: 2, V: scalarOne} - // TODO: check DistKeyShare if it needs a scheme - fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} - err = fileStore.SaveShare(fakeShare) - require.NoError(t, err) - - startArgs := []string{ - "drand", - "start", - "--private-listen", priv.Public.Address(), - "--tls-cert", certPath, - "--tls-key", keyPath, - "--control", ctrlPort, - "--folder", tmpPath, - "--metrics", metricsPort, - } - go func() { - err := CLI().Run(startArgs) - if err != nil { - t.Errorf("error while starting node: %v", err) - } - }() - - stopArgs := []string{"drand", "stop", "--control", ctrlPort} - defer func() { - err := CLI().Run(stopArgs) - if err != nil { - t.Errorf("error while stopping the node: %v", err) - } - }() - - time.Sleep(500 * time.Millisecond) - - testStartedTLSDrandFunctional(t, ctrlPort, certPath, group, priv) -} - -func testStartedTLSDrandFunctional(t *testing.T, ctrlPort, certPath string, group *key.Group, priv *key.Pair) { - t.Helper() - lg := testlogger.New(t) - - var err error - - chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-cert", certPath, priv.Public.Address()} - chainInfoBuff, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") - require.NoError(t, err) - expectedOutput := string(chainInfoBuff) - testCommand(t, chainInfoCmd, expectedOutput) - - showPublic := []string{"drand", "show", "public", "--control", ctrlPort} - b, _ := priv.Public.Key.MarshalBinary() - exp := hex.EncodeToString(b) - testCommand(t, showPublic, exp) - - showCokey := []string{"drand", "show", "chain-info", "--control", ctrlPort} - expectedOutput = string(chainInfoBuff) - testCommand(t, showCokey, expectedOutput) - - showGroup := []string{"drand", "show", "group", "--control", ctrlPort} - testCommand(t, showGroup, "") - - showHash := []string{"drand", "show", "group", "--control", ctrlPort, "--hash"} - groupHash := hex.EncodeToString(group.Hash()) - testCommand(t, showHash, groupHash) -} - -func testCommand(t *testing.T, args []string, exp string) { - t.Helper() - - var buff bytes.Buffer - t.Log("--------------") - cli := CLI() - cli.Writer = &buff - require.NoError(t, cli.Run(args)) - if exp == "" { - return - } - t.Logf("RUNNING: %v\n", args) - require.Contains(t, strings.Trim(buff.String(), "\n"), exp) -} - -// getSBFolderStructure create a new single-beacon folder structure in a temporary folder -func getSBFolderStructure(t *testing.T) string { - t.Helper() - - tmp := path.Join(t.TempDir(), "drand") - - fs.CreateSecureFolder(path.Join(tmp, key.GroupFolderName)) - fs.CreateSecureFolder(path.Join(tmp, key.FolderName)) - fs.CreateSecureFolder(path.Join(tmp, core.DefaultDBFolder)) - - return tmp -} - -func TestDrandListSchemes(t *testing.T) { - n := 2 - instances := genAndLaunchDrandInstances(t, n) - - for _, instance := range instances { - remote := []string{"drand", "util", "list-schemes", "--control", instance.ctrlPort} - - err := CLI().Run(remote) - require.NoError(t, err) - } -} - -func TestDrandReloadBeacon(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - n := 4 - instances := genAndLaunchDrandInstances(t, n) - - for i, inst := range instances { - if i == 0 { - inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) - } else { - inst.join(t, beaconID) - } - } - instances[0].executeDKG(t, beaconID) - - dkgTimeoutSeconds := 20 - require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) - t.Log("waiting for initial set up to settle on all nodes") - - defer func() { - for _, inst := range instances { - // We want to ignore this error, at least until the stop command won't return an error - // when correctly running the stop command. - t.Logf("stopping instance %v\n", inst.addr) - err := inst.stopAll() - require.NoError(t, err) - t.Logf("stopped instance %v\n", inst.addr) - } - }() - - t.Log("waiting for initial setup to finish") - time.Sleep(5 * time.Second) - - // try to reload a beacon which is already loaded - err = instances[3].load(beaconID) - require.Error(t, err) - - // Stop beacon process... not the entire node - err = instances[3].stop(beaconID) - require.NoError(t, err) - - // check the node is still alive - testPing(t, instances[3].ctrlPort) - - t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") - time.Sleep(10 * time.Second) - - // reload a beacon - err = instances[3].load(beaconID) - require.NoError(t, err) - - // test beacon process status - testStatus(t, instances[3].ctrlPort, beaconID) - - time.Sleep(3 * time.Second) - - // test beacon process status - testStatus(t, instances[3].ctrlPort, beaconID) -} - -func TestDrandLoadNotPresentBeacon(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - n := 4 - instances := genAndLaunchDrandInstances(t, n) - - for i, inst := range instances { - if i == 0 { - inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) - } else { - inst.join(t, beaconID) - } - } - instances[0].executeDKG(t, beaconID) - - dkgTimeoutSeconds := 20 - - t.Log("waiting for initial set up to settle on all nodes") - err = instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds) - if err != nil { - t.Fatal(err) - } - - defer func() { - for _, inst := range instances { - _ = inst.stopAll() - } - }() - - t.Log("waiting for initial setup to finish") - time.Sleep(5 * time.Second) - - // Stop beacon process... not the entire node - err = instances[3].stop(beaconID) - require.NoError(t, err) - - t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") - time.Sleep(10 * time.Second) - - // reload a different beacon - err = instances[3].load("not-a-valid-beacon-name-here") - require.Error(t, err) - - // test original beacon process status and hope it's still off - testFailStatus(t, instances[3].ctrlPort, beaconID) -} - -func TestDrandStatus_WithoutDKG(t *testing.T) { - n := 4 - instances := genAndLaunchDrandInstances(t, n) - allAddresses := make([]string, 0, n) - for _, instance := range instances { - allAddresses = append(allAddresses, instance.addr) - } - - // check that each node can reach each other - for i, instance := range instances { - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - remote = append(remote, allAddresses...) - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - require.Contains(t, buff.String(), instance.addr+" -> OK") - } - } - // stop one and check that all nodes report this node down - toStop := 2 - insToStop := instances[toStop] - err := insToStop.stopAll() - require.NoError(t, err) - - for i, instance := range instances { - if i == toStop { - continue - } - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - remote = append(remote, allAddresses...) - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - if j != toStop { - require.Contains(t, buff.String(), instance.addr+" -> OK") - } else { - require.Contains(t, buff.String(), instance.addr+" -> X") - } - } - } -} - -func TestDrandStatus_WithDKG_NoAddress(t *testing.T) { - if testing.Short() { - t.Skip("skipping slow test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - n := 4 - instances := genAndLaunchDrandInstances(t, n) - - for i, inst := range instances { - if i == 0 { - inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) - } else { - inst.join(t, beaconID) - } - } - instances[0].executeDKG(t, beaconID) - - dkgTimeoutSeconds := 20 - require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) - t.Log("waiting for initial set up to settle on all nodes") - - // check that each node can reach each other - for i, instance := range instances { - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - require.Contains(t, buff.String(), instance.addr+" -> OK") - } - } - // stop one and check that all nodes report this node down - toStop := 2 - insToStop := instances[toStop] - err = insToStop.stopAll() - require.NoError(t, err) - - for i, instance := range instances { - if i == toStop { - continue - } - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - if j != toStop { - require.Contains(t, buff.String(), instance.addr+" -> OK") - } else { - require.Contains(t, buff.String(), instance.addr+" -> X") - } - } - } -} - -func TestDrandStatus_WithDKG_OneAddress(t *testing.T) { - if testing.Short() { - t.Skip("skipping slow test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - n := 4 - instances := genAndLaunchDrandInstances(t, n) - - for i, inst := range instances { - if i == 0 { - inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) - } else { - inst.join(t, beaconID) - } - } - instances[0].executeDKG(t, beaconID) - - dkgTimeoutSeconds := 20 - require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) - t.Log("waiting for initial set up to settle on all nodes") - - // check that each node can reach each other - for i, instance := range instances { - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - remote = append(remote, instances[i].addr) - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - require.Contains(t, buff.String(), instance.addr+" -> OK") - } - } - // stop one and check that all nodes report this node down - toStop := 2 - insToStop := instances[toStop] - err = insToStop.stopAll() - require.NoError(t, err) - - for i, instance := range instances { - if i == toStop { - continue - } - remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} - remote = append(remote, instances[i].addr) - var buff bytes.Buffer - - cli := CLI() - cli.Writer = &buff - - err := cli.Run(remote) - require.NoError(t, err) - for j, instance := range instances { - if i == j { - continue - } - if j != toStop { - require.Contains(t, buff.String(), instance.addr+" -> OK") - } else { - require.Contains(t, buff.String(), instance.addr+" -> X") - } - } - } -} - -func TestEmptyPortSelectionUsesDefaultDuringKeygen(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := t.TempDir() - app := CLI() - - // args are missing a port for the node address - args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} - // after being prompted for a port, the 'user' hits enter to select the default - app.Reader = strings.NewReader("\n") - - require.NoError(t, app.Run(args)) -} - -func TestValidPortSelectionSucceedsDuringKeygen(t *testing.T) { - beaconID := test.GetBeaconIDFromEnv() - - tmp := t.TempDir() - app := CLI() - - args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} - app.Reader = strings.NewReader("8080\n") - - require.NoError(t, app.Run(args)) -} - -type drandInstance struct { - path string - ctrlPort string - addr string - metrics string - certPath string - keyPath string - certsDir string -} - -func (d *drandInstance) stopAll() error { - return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort}) -} - -func (d *drandInstance) stop(beaconID string) error { - return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort, "--id", beaconID}) -} - -func (d *drandInstance) startInitialDKG( - t *testing.T, - l log.Logger, - instances []*drandInstance, - threshold, - //nolint:unparam // This is a parameter - periodSeconds int, - beaconID string, - sch *crypto.Scheme, -) { - t.Helper() - - addrs := make([]string, len(instances)) - for i, v := range instances { - addrs[i] = v.ctrlPort - } - - proposal, err := generateJoiningProposal(l, "default", addrs) - require.NoError(t, err) - - proposalPath := filepath.Join(t.TempDir(), "proposal.toml") - err = os.WriteFile(proposalPath, []byte(proposal), 0755) - require.NoError(t, err) - - dkgArgs := []string{ - "drand", - "dkg", - "propose", - "--proposal", proposalPath, - "--transition-time", fmt.Sprintf("%ds", 30*periodSeconds), - "--catchup-period", fmt.Sprintf("%ds", periodSeconds/2), - "--threshold", fmt.Sprintf("%d", threshold), - "--period", fmt.Sprintf("%ds", periodSeconds), - "--control", d.ctrlPort, - "--scheme", sch.Name, - "--id", beaconID, - } - - err = CLI().Run(dkgArgs) - require.NoError(t, err) -} - -func (d *drandInstance) executeDKG(t *testing.T, beaconID string) { - t.Helper() - dkgArgs := []string{ - "drand", - "dkg", - "execute", - "--control", d.ctrlPort, - "--id", beaconID, - } - - err := CLI().Run(dkgArgs) - require.NoError(t, err) -} - -func (d *drandInstance) awaitDKGComplete( - t *testing.T, - beaconID string, - //nolint:unparam // This is a parameter - epoch uint32, - timeoutSeconds int, -) error { - t.Helper() - dkgArgs := []string{ - "drand", - "dkg", - "status", - "--control", d.ctrlPort, - "--id", beaconID, - "--format", "csv", - } - - for i := 0; i < timeoutSeconds; i++ { - cli := CLI() - var buf bytes.Buffer - cli.Writer = &buf - - err := cli.Run(dkgArgs) - if err != nil { - return err - } - - statusOutput := buf.String() - expected := fmt.Sprintf("State:Complete,Epoch:%d,", epoch) - - if strings.Contains(statusOutput, expected) { - return nil - } - time.Sleep(1 * time.Second) - } - - return errors.New("DKG didn't complete within the timeout") -} - -func (d *drandInstance) load(beaconID string) error { - reloadArgs := []string{ - "drand", - "load", - "--control", d.ctrlPort, - "--id", beaconID, - } - - return CLI().Run(reloadArgs) -} - -func (d *drandInstance) run(t *testing.T, beaconID string) { - t.Helper() - - d.runWithStartArgs(t, beaconID, nil) -} - -func (d *drandInstance) runWithStartArgs(t *testing.T, beaconID string, startArgs []string) { - t.Helper() - - require.Equal(t, 0, len(startArgs)%2, "start args must be in pairs of option/value") - - baseArgs := []string{ - "drand", - "start", - "--verbose", - "--tls-cert", d.certPath, - "--tls-key", d.keyPath, - "--certs-dir", d.certsDir, - "--control", d.ctrlPort, - "--folder", d.path, - "--metrics", d.metrics, - "--private-listen", d.addr, - } - - baseArgs = append(baseArgs, startArgs...) - - go func() { - err := CLI().Run(baseArgs) - require.NoError(t, err) - }() - - // Prevent race condition in urfave/cli - time.Sleep(100 * time.Millisecond) - - // make sure we run each one sequentially - testStatus(t, d.ctrlPort, beaconID) -} - -func (d *drandInstance) join(t *testing.T, id string) { - t.Helper() - joinArgs := []string{ - "drand", - "dkg", - "join", - "--id", - id, - "--control", - d.ctrlPort, - } - - err := CLI().Run(joinArgs) - require.NoError(t, err) -} - -func genAndLaunchDrandInstances(t *testing.T, n int) []*drandInstance { - t.Helper() - - beaconID := test.GetBeaconIDFromEnv() - - ins := genDrandInstances(t, beaconID, n) - return launchDrandInstances(t, beaconID, ins) -} - -func genDrandInstances(t *testing.T, beaconID string, n int) []*drandInstance { - t.Helper() - - tmpPath := t.TempDir() - - certsDir := path.Join(tmpPath, "certs") - require.NoError(t, os.Mkdir(certsDir, 0o740)) - l := testlogger.New(t) - - ins := make([]*drandInstance, 0, n) - for i := 1; i <= n; i++ { - nodePath, err := os.MkdirTemp(tmpPath, "node") - require.NoError(t, err) - - certPath := path.Join(nodePath, "cert") - keyPath := path.Join(nodePath, "tls.key") - pubPath := path.Join(tmpPath, "pub.key") - - freePort := test.FreePort() - addr := "127.0.0.1:" + freePort - ctrlPort := test.FreePort() - metricsPort := test.FreePort() - - // generate key so it loads - // TODO let's remove this requirement - no need for longterm keys - priv, err := key.NewTLSKeyPair(addr, nil) - require.NoError(t, err) - require.NoError(t, key.Save(pubPath, priv.Public, false)) - config := core.NewConfig(l, core.WithConfigFolder(nodePath)) - fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) - err = fileStore.SaveKeyPair(priv) - require.NoError(t, err) - - h, _, err := gnet.SplitHostPort(addr) - require.NoError(t, err) - - err = httpscerts.Generate(certPath, keyPath, h) - require.NoError(t, err) - - // copy into one folder for giving a common CERT folder - _, err = exec.Command("cp", certPath, path.Join(certsDir, fmt.Sprintf("cert-%d", i))).Output() - require.NoError(t, err) - - ins = append(ins, &drandInstance{ - addr: addr, - ctrlPort: ctrlPort, - path: nodePath, - keyPath: keyPath, - metrics: metricsPort, - certPath: certPath, - certsDir: certsDir, - }) - } - - return ins -} - -func launchDrandInstances(t *testing.T, beaconID string, ins []*drandInstance) []*drandInstance { - t.Helper() - - for _, instance := range ins { - instance.run(t, beaconID) - } - return ins -} - -//nolint:funlen // This is a test -func TestMemDBBeaconReJoinsNetworkAfterLongStop(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - // How many rounds to generate while the node is stopped. - roundsWhileMissing := 50 - period := 1 - n := 4 - instances := genDrandInstances(t, beaconID, n) - memDBNodeID := len(instances) - 1 - - for i := 0; i < memDBNodeID; i++ { - inst := instances[i] - inst.run(t, beaconID) - } - - instances[memDBNodeID].runWithStartArgs(t, beaconID, []string{"--db", "memdb"}) - memDBNode := instances[memDBNodeID] - - for i, inst := range instances { - inst := inst - if i == 0 { - inst.startInitialDKG(t, l, instances, 3, period, beaconID, sch) - // Wait a bit after launching the leader to launch the other nodes too. - time.Sleep(500 * time.Millisecond) - } else { - inst.join(t, beaconID) - } - } - - instances[0].executeDKG(t, beaconID) - - t.Log("waiting for initial set up to settle on all nodes") - err = instances[0].awaitDKGComplete(t, beaconID, 1, 60) - require.NoError(t, err) - - defer func() { - for _, inst := range instances { - // We want to ignore this error, at least until the stop command won't return an error - // when correctly running the stop command. - t.Logf("stopping instance %v\n", inst.addr) - err := inst.stopAll() - require.NoError(t, err) - t.Logf("stopped instance %v\n", inst.addr) - } - }() - - memDBClient, err := net.NewControlClient(l, memDBNode.ctrlPort) - require.NoError(t, err) - - chainInfo, err := memDBClient.ChainInfo(beaconID) - require.NoError(t, err) - - // Wait until DKG finishes - secondsToGenesisTime := chainInfo.GenesisTime - time.Now().Unix() - t.Logf("waiting %ds until DKG finishes\n", secondsToGenesisTime) - time.Sleep(time.Duration(secondsToGenesisTime) * time.Second) - - // Wait for some rounds to be generated - t.Log("wait for some rounds to be generated") - time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) - - // Get the status before stopping the node - status, err := memDBClient.Status(beaconID) - require.NoError(t, err) - - require.False(t, status.ChainStore.IsEmpty) - require.NotZero(t, status.ChainStore.LastRound) - - lastRoundBeforeShutdown := status.ChainStore.LastRound - - // Stop beacon process... not the entire node - err = instances[memDBNodeID].stop(beaconID) - require.NoError(t, err) - - t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") - time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) - - // reload a beacon - err = instances[memDBNodeID].load(beaconID) - require.NoError(t, err) - - // Wait a bit to allow the node to startup and load correctly - time.Sleep(2 * time.Second) - - status, err = memDBClient.Status(beaconID) - require.NoError(t, err) - - require.False(t, status.ChainStore.IsEmpty) - require.NotZero(t, status.ChainStore.LastRound) - expectedRound := lastRoundBeforeShutdown + uint64(roundsWhileMissing) - t.Logf("comparing lastRound %d with lastRoundBeforeShutdown %d\n", status.ChainStore.LastRound, expectedRound) - require.GreaterOrEqual(t, status.ChainStore.LastRound, expectedRound) -} - -func TestDKGStatusDoesntBlowUp(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - l := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - beaconID := test.GetBeaconIDFromEnv() - - // start some nodes - n := 4 - instances := genAndLaunchDrandInstances(t, n) - - // execute a DKG - for i, inst := range instances { - if i == 0 { - inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) - } else { - inst.join(t, beaconID) - } - } - instances[0].executeDKG(t, beaconID) - - // wait for the DKG to finish - dkgTimeoutSeconds := 20 - require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) - t.Log("waiting for initial set up to settle on all nodes") - - // check the status command runs fine - err = CLI().Run([]string{"drand", "dkg", "status", "--control", instances[0].ctrlPort}) - require.NoError(t, err) -} +//import ( +// "bytes" +// "context" +// "encoding/hex" +// "errors" +// "fmt" +// gnet "net" +// "os" +// "os/exec" +// "path" +// "path/filepath" +// "strconv" +// "strings" +// "testing" +// "time" +// +// "github.com/BurntSushi/toml" +// "github.com/kabukky/httpscerts" +// json "github.com/nikkolasg/hexjson" +// "github.com/stretchr/testify/require" +// +// "github.com/drand/drand-cli/internal/chain" +// "github.com/drand/drand-cli/internal/chain/boltdb" +// "github.com/drand/drand-cli/internal/core" +// dkg2 "github.com/drand/drand-cli/internal/dkg" +// "github.com/drand/drand-cli/internal/fs" +// "github.com/drand/drand-cli/internal/net" +// "github.com/drand/drand-cli/internal/test" +// "github.com/drand/drand-cli/internal/test/testlogger" +// "github.com/drand/drand/common" +// chain2 "github.com/drand/drand/common/chain" +// "github.com/drand/drand/common/key" +// "github.com/drand/drand/common/log" +// "github.com/drand/drand/crypto" +// "github.com/drand/kyber" +// "github.com/drand/kyber/share" +// "github.com/drand/kyber/share/dkg" +// "github.com/drand/kyber/util/random" +//) +// +//func TestMigrate(t *testing.T) { +// tmp := getSBFolderStructure(t) +// +// args := []string{"drand", "util", "migrate", "--folder", tmp} +// app := CLI() +// require.NoError(t, app.Run(args)) +// +// l := testlogger.New(t) +// config := core.NewConfig(l, core.WithConfigFolder(tmp)) +// defaultBeaconPath := path.Join(config.ConfigFolderMB(), common.DefaultBeaconID) +// +// newGroupFilePath := path.Join(defaultBeaconPath, key.GroupFolderName) +// newKeyFilePath := path.Join(defaultBeaconPath, key.FolderName) +// newDBFilePath := path.Join(defaultBeaconPath, core.DefaultDBFolder) +// +// if !fs.FolderExists(defaultBeaconPath, newGroupFilePath) { +// t.Errorf("group folder should have been migrated") +// } +// if !fs.FolderExists(defaultBeaconPath, newKeyFilePath) { +// t.Errorf("key folder should have been migrated") +// } +// if !fs.FolderExists(defaultBeaconPath, newDBFilePath) { +// t.Errorf("db folder should have been migrated") +// } +//} +// +//func TestResetError(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := getSBFolderStructure(t) +// +// args := []string{"drand", "util", "reset", "--folder", tmp, "--id", beaconID} +// app := CLI() +// require.Error(t, app.Run(args)) +//} +// +//func TestDeleteBeaconError(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := getSBFolderStructure(t) +// +// // that command should delete round 3 and 4 +// args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} +// app := CLI() +// require.Error(t, app.Run(args)) +//} +// +//func TestDeleteBeacon(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// l := testlogger.New(t) +// ctx := context.Background() +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// if sch.Name == crypto.DefaultSchemeID { +// ctx = chain.SetPreviousRequiredOnContext(ctx) +// } +// tmp := path.Join(t.TempDir(), "drand") +// +// opt := core.WithConfigFolder(tmp) +// conf := core.NewConfig(l, opt) +// fs.CreateSecureFolder(conf.DBFolder(beaconID)) +// store, err := boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) +// require.NoError(t, err) +// err = store.Put(ctx, &common.Beacon{ +// Round: 1, +// Signature: []byte("Hello"), +// }) +// require.NoError(t, err) +// err = store.Put(ctx, &common.Beacon{ +// Round: 2, +// Signature: []byte("Hello"), +// }) +// require.NoError(t, err) +// err = store.Put(ctx, &common.Beacon{ +// Round: 3, +// Signature: []byte("Hello"), +// }) +// require.NoError(t, err) +// err = store.Put(ctx, &common.Beacon{ +// Round: 4, +// Signature: []byte("hello"), +// }) +// require.NoError(t, err) +// // try to fetch round 3 and 4 +// b, err := store.Get(ctx, 3) +// require.NoError(t, err) +// require.NotNil(t, b) +// b, err = store.Get(ctx, 4) +// require.NoError(t, err) +// require.NotNil(t, b) +// +// err = store.Close() +// require.NoError(t, err) +// +// args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} +// app := CLI() +// require.NoError(t, app.Run(args)) +// +// store, err = boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) +// require.NoError(t, err) +// +// // try to fetch round 3 and 4 - it should now fail +// _, err = store.Get(ctx, 3) +// require.Error(t, err) +// +// _, err = store.Get(ctx, 4) +// require.Error(t, err) +//} +// +//func TestKeySelfSignError(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := getSBFolderStructure(t) +// +// args := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} +// app := CLI() +// require.Error(t, app.Run(args)) +//} +// +//func TestKeySelfSign(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// l := testlogger.New(t) +// +// tmp := path.Join(t.TempDir(), "drand") +// +// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} +// require.NoError(t, CLI().Run(args)) +// +// selfSign := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} +// // try self sign, it should only print that it's already the case +// expectedOutput := "already self signed" +// testCommand(t, selfSign, expectedOutput) +// +// // load, remove signature and save +// config := core.NewConfig(l, core.WithConfigFolder(tmp)) +// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) +// +// pair, err := fileStore.LoadKeyPair(nil) +// require.NoError(t, err) +// pair.Public.Signature = nil +// require.NoError(t, fileStore.SaveKeyPair(pair)) +// +// expectedOutput = "identity self signed" +// testCommand(t, selfSign, expectedOutput) +//} +// +//func TestKeyGenError(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := getSBFolderStructure(t) +// +// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} +// app := CLI() +// require.Error(t, app.Run(args)) +//} +// +//func TestKeyGen(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// l := testlogger.New(t) +// +// tmp := path.Join(t.TempDir(), "drand") +// sch, _ := crypto.GetSchemeFromEnv() +// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "--scheme", sch.Name, "127.0.0.1:8081"} +// require.NoError(t, CLI().Run(args)) +// +// config := core.NewConfig(l, core.WithConfigFolder(tmp)) +// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) +// priv, err := fileStore.LoadKeyPair(nil) +// require.NoError(t, err) +// require.NotNil(t, priv.Public) +// +// tmp2 := path.Join(t.TempDir(), "drand2") +// +// args = []string{"drand", "generate-keypair", "--folder", tmp2, "--id", beaconID, "--scheme", sch.Name} +// require.Error(t, CLI().Run(args)) +// +// config = core.NewConfig(l, core.WithConfigFolder(tmp2)) +// fileStore = key.NewFileStore(config.ConfigFolderMB(), beaconID) +// priv, err = fileStore.LoadKeyPair(nil) +// require.Error(t, err) +// require.Nil(t, priv) +//} +// +//// tests valid commands and then invalid commands +//func TestStartAndStop(t *testing.T) { +// tmpPath := t.TempDir() +// +// n := 5 +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// _, group := test.BatchIdentities(n, sch, beaconID) +// groupPath := path.Join(tmpPath, "group.toml") +// require.NoError(t, key.Save(groupPath, group, false)) +// +// privateAddr := test.Addresses(1)[0] +// +// args := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmpPath, "--id", beaconID, privateAddr} +// require.NoError(t, CLI().Run(args)) +// +// startCh := make(chan bool) +// go func() { +// startArgs := []string{"drand", "start", "--tls-disable", "--folder", tmpPath, "--private-listen", privateAddr} +// // Allow the rest of the test to start +// // Any error will be caught in the error check below +// startCh <- true +// err := CLI().Run(startArgs) +// if err != nil { +// t.Errorf("error starting the node %s\n", err) +// t.Fail() +// return +// } +// // After we finish the execution, flag that we finished. +// // This allows the test to exit cleanly without reaching the +// // timeout at the end. +// startCh <- true +// // TODO : figuring out how to not panic in grpc call +// // ERROR: 2020/01/23 21:06:28 grpc: server failed to encode response: +// // rpc error: code = Internal desc = grpc: error while marshaling: proto: +// // Marshal called with nil +// }() +// <-startCh +// time.Sleep(200 * time.Millisecond) +// +// stopArgs := []string{"drand", "stop"} +// err = CLI().Run(stopArgs) +// require.NoError(t, err) +// +// select { +// case <-startCh: +// case <-time.After(1 * time.Second): +// t.Fatal("drand daemon did not stop") +// } +//} +// +//func TestUtilCheckReturnsErrorForPortNotMatchingKeypair(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := t.TempDir() +// +// // try to generate a keypair and make it listen on another address +// keyPort := test.FreePort() +// keyAddr := "127.0.0.1:" + keyPort +// generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} +// require.NoError(t, CLI().Run(generate)) +// +// listenPort := test.FreePort() +// listenAddr := "127.0.0.1:" + listenPort +// listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", listenAddr, "--folder", tmp} +// ctx, cancel := context.WithCancel(context.Background()) +// defer cancel() +// +// waitCh := make(chan bool) +// go func() { +// waitCh <- true +// err := CLI().RunContext(ctx, listen) +// if err != nil { +// t.Errorf("error while starting the node %v\n", err) +// t.Fail() +// return +// } +// }() +// <-waitCh +// // TODO can we maybe try to bind continuously to not having to wait +// time.Sleep(200 * time.Millisecond) +// +// // run the check tool it should fail because key and address are not +// // consistent +// check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, listenAddr} +// require.Error(t, CLI().Run(check)) +//} +// +//func TestUtilCheckSucceedsForPortMatchingKeypair(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := t.TempDir() +// +// keyPort := test.FreePort() +// keyAddr := "127.0.0.1:" + keyPort +// generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} +// require.NoError(t, CLI().Run(generate)) +// +// listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", keyAddr, "--folder", tmp} +// ctx, cancel := context.WithCancel(context.Background()) +// defer cancel() +// +// waitCh := make(chan bool) +// go func() { +// waitCh <- true +// err := CLI().RunContext(ctx, listen) +// if err != nil { +// t.Errorf("error while starting the node %v\n", err) +// t.Fail() +// return +// } +// }() +// <-waitCh +// // TODO can we maybe try to bind continuously to not having to wait +// time.Sleep(200 * time.Millisecond) +// +// check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, keyAddr} +// require.NoError(t, CLI().Run(check)) +//} +// +////nolint:funlen +//func TestStartWithoutGroup(t *testing.T) { +// lg := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// tmpPath := path.Join(t.TempDir(), "drand") +// require.NoError(t, os.Mkdir(tmpPath, 0o740)) +// +// pubPath := path.Join(tmpPath, "pub.key") +// port1, _ := strconv.Atoi(test.FreePort()) +// addr := "127.0.0.1:" + strconv.Itoa(port1) +// +// ctrlPort1, ctrlPort2, metricsPort := test.FreePort(), test.FreePort(), test.FreePort() +// +// priv, err := key.NewKeyPair(addr, sch) +// require.NoError(t, err) +// require.NoError(t, key.Save(pubPath, priv.Public, false)) +// +// config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) +// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) +// require.NoError(t, fileStore.SaveKeyPair(priv)) +// +// startArgs := []string{ +// "drand", +// "start", +// "--private-listen", priv.Public.Address(), +// "--tls-disable", +// "--verbose", +// "--folder", tmpPath, +// "--control", ctrlPort1, +// "--metrics", "127.0.0.1:" + metricsPort, +// } +// +// go func() { +// err := CLI().Run(startArgs) +// if err != nil { +// t.Errorf(err.Error()) +// } +// }() +// +// time.Sleep(500 * time.Millisecond) +// +// t.Log("--- DRAND SHARE --- (expected to fail)") +// // this must fail because not enough arguments +// // TODO - test vectors testing on the inputs +// +// initDKGArgs := []string{"drand", "share", "--control", ctrlPort1, "--id", beaconID} +// require.Error(t, CLI().Run(initDKGArgs)) +// +// t.Log("--- DRAND STOP --- (failing instance)") +// err = CLI().Run([]string{"drand", "stop", "--control", ctrlPort1}) +// require.NoError(t, err) +// +// t.Log(" --- DRAND GROUP ---") +// +// // fake group +// _, group := test.BatchIdentities(5, sch, beaconID) +// +// // fake dkg output +// fakeKey := sch.KeyGroup.Point().Pick(random.New()) +// distKey := &key.DistPublic{ +// Coefficients: []kyber.Point{ +// fakeKey, +// sch.KeyGroup.Point().Pick(random.New()), +// sch.KeyGroup.Point().Pick(random.New()), +// }, +// } +// priv.Public.TLS = false +// +// group.Period = 5 * time.Second +// group.GenesisTime = time.Now().Unix() - 10 +// group.PublicKey = distKey +// group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} +// group.Nodes[1] = &key.Node{Identity: priv.Public, Index: 1} +// groupPath := path.Join(tmpPath, "drand_group.toml") +// require.NoError(t, key.Save(groupPath, group, false)) +// +// // save it also to somewhere drand will find it +// require.NoError(t, fileStore.SaveGroup(group)) +// +// // fake share +// scalarOne := sch.KeyGroup.Scalar().One() +// s := &share.PriShare{I: 2, V: scalarOne} +// fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} +// require.NoError(t, fileStore.SaveShare(fakeShare)) +// +// // save a fake complete DKG in the store +// dStore, err := dkg2.NewDKGStore(tmpPath, nil) +// require.NoError(t, err) +// err = dStore.SaveFinished(beaconID, &dkg2.DBState{ +// BeaconID: beaconID, +// Epoch: 1, +// State: dkg2.Complete, +// Threshold: 1, +// Timeout: time.Unix(2549084715, 0).UTC(), // this will need updated in 2050 :^) +// SchemeID: sch.Name, +// GenesisTime: time.Unix(1669718523, 0).UTC(), +// GenesisSeed: []byte("deadbeef"), +// TransitionTime: time.Unix(1669718523, 0).UTC(), +// CatchupPeriod: 5 * time.Second, +// BeaconPeriod: 10 * time.Second, +// +// Leader: nil, +// Remaining: nil, +// Joining: nil, +// Leaving: nil, +// +// Acceptors: nil, +// Rejectors: nil, +// +// FinalGroup: group, +// KeyShare: fakeShare, +// }) +// require.NoError(t, err) +// +// // Have to close it afterwards or starting the node will become unresponsive +// err = dStore.Close() +// require.NoError(t, err) +// +// t.Logf(" --- DRAND START --- control %s\n", ctrlPort2) +// +// start2 := []string{ +// "drand", +// "start", +// "--control", ctrlPort2, +// "--private-listen", priv.Public.Address(), +// "--tls-disable", +// "--folder", tmpPath, +// "--verbose", +// } +// +// go func() { +// err := CLI().Run(start2) +// if err != nil { +// t.Errorf("error while starting second node: %v", err) +// } +// }() +// +// stop2 := []string{"drand", "stop", "--control", ctrlPort2} +// defer func() { +// err := CLI().Run(stop2) +// if err != nil { +// t.Errorf("error while stopping second node: %v", err) +// } +// }() +// +// time.Sleep(500 * time.Millisecond) +// +// testStartedDrandFunctional(t, ctrlPort2, tmpPath, priv.Public.Address(), group, fileStore, beaconID) +//} +// +//func testStartedDrandFunctional(t *testing.T, ctrlPort, rootPath, address string, group *key.Group, fileStore key.Store, beaconID string) { +// t.Helper() +// lg := testlogger.New(t) +// +// testPing(t, ctrlPort) +// testStatus(t, ctrlPort, beaconID) +// testListSchemes(t, ctrlPort) +// +// require.NoError(t, toml.NewEncoder(os.Stdout).Encode(group.TOML())) +// +// t.Log("Running CHAIN-INFO command") +// chainInfo, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") +// require.NoError(t, err) +// expectedOutput := string(chainInfo) +// chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-disable", address} +// testCommand(t, chainInfoCmd, expectedOutput) +// +// t.Log("Running CHAIN-INFO --HASH command") +// chainInfoCmdHash := []string{"drand", "get", "chain-info", "--hash", "--tls-disable", address} +// expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) +// testCommand(t, chainInfoCmdHash, expectedOutput) +// +// showChainInfo := []string{"drand", "show", "chain-info", "--control", ctrlPort} +// buffCi, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") +// require.NoError(t, err) +// testCommand(t, showChainInfo, string(buffCi)) +// +// showChainInfo = []string{"drand", "show", "chain-info", "--hash", "--control", ctrlPort} +// expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) +// testCommand(t, showChainInfo, expectedOutput) +// +// // reset state +// resetCmd := []string{"drand", "util", "reset", "--folder", rootPath, "--id", beaconID} +// r, w, err := os.Pipe() +// require.NoError(t, err) +// _, err = w.WriteString("y\n") +// require.NoError(t, err) +// os.Stdin = r +// require.NoError(t, CLI().Run(resetCmd)) +// _, err = fileStore.LoadShare(nil) +// require.Error(t, err) +// _, err = fileStore.LoadGroup() +// require.Error(t, err) +//} +// +//func testPing(t *testing.T, ctrlPort string) { +// t.Helper() +// +// var err error +// +// t.Logf(" + running PING command with %s\n", ctrlPort) +// for i := 0; i < 3; i++ { +// ping := []string{"drand", "util", "ping", "--control", ctrlPort} +// err = CLI().Run(ping) +// if err == nil { +// break +// } +// time.Sleep(500 * time.Millisecond) +// } +// require.NoError(t, err) +//} +// +//func testStatus(t *testing.T, ctrlPort, beaconID string) { +// t.Helper() +// +// var err error +// +// t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) +// for i := 0; i < 3; i++ { +// status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} +// err = CLI().Run(status) +// if err == nil { +// return +// } +// time.Sleep(500 * time.Millisecond) +// } +// require.NoError(t, err) +//} +// +//func testFailStatus(t *testing.T, ctrlPort, beaconID string) { +// t.Helper() +// +// var err error +// +// t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) +// for i := 0; i < 3; i++ { +// status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} +// err = CLI().Run(status) +// require.Error(t, err) +// time.Sleep(500 * time.Millisecond) +// } +//} +// +//func testListSchemes(t *testing.T, ctrlPort string) { +// t.Helper() +// +// var err error +// +// t.Logf(" + running list schemes command with %s\n", ctrlPort) +// for i := 0; i < 3; i++ { +// schemes := []string{"drand", "util", "list-schemes", "--control", ctrlPort} +// err = CLI().Run(schemes) +// if err == nil { +// break +// } +// time.Sleep(500 * time.Millisecond) +// } +// require.NoError(t, err) +//} +// +////nolint:funlen //This is a test +//func TestClientTLS(t *testing.T) { +// t.Skip("The test fails because the logic for generating the group has changed") +// lg := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// tmpPath := path.Join(t.TempDir(), "drand") +// require.NoError(t, os.Mkdir(tmpPath, 0o740)) +// +// groupPath := path.Join(tmpPath, "group.toml") +// certPath := path.Join(tmpPath, "server.pem") +// keyPath := path.Join(tmpPath, "key.pem") +// pubPath := path.Join(tmpPath, "pub.key") +// +// freePort := test.FreePort() +// addr := "127.0.0.1:" + freePort +// ctrlPort := test.FreePort() +// metricsPort := test.FreePort() +// +// priv, err := key.NewTLSKeyPair(addr, nil) +// require.NoError(t, err) +// require.NoError(t, key.Save(pubPath, priv.Public, false)) +// +// config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) +// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) +// err = fileStore.SaveKeyPair(priv) +// require.NoError(t, err) +// +// if httpscerts.Check(certPath, keyPath) != nil { +// t.Log("generating on the fly") +// h, _, err := gnet.SplitHostPort(priv.Public.Address()) +// require.NoError(t, err) +// err = httpscerts.Generate(certPath, keyPath, h) +// require.NoError(t, err) +// } +// +// // fake group +// _, group := test.BatchTLSIdentities(5, sch, beaconID) +// // fake dkg outuput +// fakeKey := sch.KeyGroup.Point().Pick(random.New()) +// // need a threshold of coefficients +// distKey := &key.DistPublic{ +// Coefficients: []kyber.Point{ +// fakeKey, +// sch.KeyGroup.Point().Pick(random.New()), +// sch.KeyGroup.Point().Pick(random.New()), +// }, +// } +// group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} +// group.Period = 2 * time.Minute +// group.GenesisTime = time.Now().Unix() +// group.PublicKey = distKey +// require.NoError(t, fileStore.SaveGroup(group)) +// require.NoError(t, key.Save(groupPath, group, false)) +// +// // fake share +// scalarOne := sch.KeyGroup.Scalar().One() +// s := &share.PriShare{I: 2, V: scalarOne} +// // TODO: check DistKeyShare if it needs a scheme +// fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} +// err = fileStore.SaveShare(fakeShare) +// require.NoError(t, err) +// +// startArgs := []string{ +// "drand", +// "start", +// "--private-listen", priv.Public.Address(), +// "--tls-cert", certPath, +// "--tls-key", keyPath, +// "--control", ctrlPort, +// "--folder", tmpPath, +// "--metrics", metricsPort, +// } +// go func() { +// err := CLI().Run(startArgs) +// if err != nil { +// t.Errorf("error while starting node: %v", err) +// } +// }() +// +// stopArgs := []string{"drand", "stop", "--control", ctrlPort} +// defer func() { +// err := CLI().Run(stopArgs) +// if err != nil { +// t.Errorf("error while stopping the node: %v", err) +// } +// }() +// +// time.Sleep(500 * time.Millisecond) +// +// testStartedTLSDrandFunctional(t, ctrlPort, certPath, group, priv) +//} +// +//func testStartedTLSDrandFunctional(t *testing.T, ctrlPort, certPath string, group *key.Group, priv *key.Pair) { +// t.Helper() +// lg := testlogger.New(t) +// +// var err error +// +// chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-cert", certPath, priv.Public.Address()} +// chainInfoBuff, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") +// require.NoError(t, err) +// expectedOutput := string(chainInfoBuff) +// testCommand(t, chainInfoCmd, expectedOutput) +// +// showPublic := []string{"drand", "show", "public", "--control", ctrlPort} +// b, _ := priv.Public.Key.MarshalBinary() +// exp := hex.EncodeToString(b) +// testCommand(t, showPublic, exp) +// +// showCokey := []string{"drand", "show", "chain-info", "--control", ctrlPort} +// expectedOutput = string(chainInfoBuff) +// testCommand(t, showCokey, expectedOutput) +// +// showGroup := []string{"drand", "show", "group", "--control", ctrlPort} +// testCommand(t, showGroup, "") +// +// showHash := []string{"drand", "show", "group", "--control", ctrlPort, "--hash"} +// groupHash := hex.EncodeToString(group.Hash()) +// testCommand(t, showHash, groupHash) +//} +// +//func testCommand(t *testing.T, args []string, exp string) { +// t.Helper() +// +// var buff bytes.Buffer +// t.Log("--------------") +// cli := CLI() +// cli.Writer = &buff +// require.NoError(t, cli.Run(args)) +// if exp == "" { +// return +// } +// t.Logf("RUNNING: %v\n", args) +// require.Contains(t, strings.Trim(buff.String(), "\n"), exp) +//} +// +//// getSBFolderStructure create a new single-beacon folder structure in a temporary folder +//func getSBFolderStructure(t *testing.T) string { +// t.Helper() +// +// tmp := path.Join(t.TempDir(), "drand") +// +// fs.CreateSecureFolder(path.Join(tmp, key.GroupFolderName)) +// fs.CreateSecureFolder(path.Join(tmp, key.FolderName)) +// fs.CreateSecureFolder(path.Join(tmp, core.DefaultDBFolder)) +// +// return tmp +//} +// +//func TestDrandListSchemes(t *testing.T) { +// n := 2 +// instances := genAndLaunchDrandInstances(t, n) +// +// for _, instance := range instances { +// remote := []string{"drand", "util", "list-schemes", "--control", instance.ctrlPort} +// +// err := CLI().Run(remote) +// require.NoError(t, err) +// } +//} +// +//func TestDrandReloadBeacon(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// +// for i, inst := range instances { +// if i == 0 { +// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) +// } else { +// inst.join(t, beaconID) +// } +// } +// instances[0].executeDKG(t, beaconID) +// +// dkgTimeoutSeconds := 20 +// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) +// t.Log("waiting for initial set up to settle on all nodes") +// +// defer func() { +// for _, inst := range instances { +// // We want to ignore this error, at least until the stop command won't return an error +// // when correctly running the stop command. +// t.Logf("stopping instance %v\n", inst.addr) +// err := inst.stopAll() +// require.NoError(t, err) +// t.Logf("stopped instance %v\n", inst.addr) +// } +// }() +// +// t.Log("waiting for initial setup to finish") +// time.Sleep(5 * time.Second) +// +// // try to reload a beacon which is already loaded +// err = instances[3].load(beaconID) +// require.Error(t, err) +// +// // Stop beacon process... not the entire node +// err = instances[3].stop(beaconID) +// require.NoError(t, err) +// +// // check the node is still alive +// testPing(t, instances[3].ctrlPort) +// +// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") +// time.Sleep(10 * time.Second) +// +// // reload a beacon +// err = instances[3].load(beaconID) +// require.NoError(t, err) +// +// // test beacon process status +// testStatus(t, instances[3].ctrlPort, beaconID) +// +// time.Sleep(3 * time.Second) +// +// // test beacon process status +// testStatus(t, instances[3].ctrlPort, beaconID) +//} +// +//func TestDrandLoadNotPresentBeacon(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// +// for i, inst := range instances { +// if i == 0 { +// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) +// } else { +// inst.join(t, beaconID) +// } +// } +// instances[0].executeDKG(t, beaconID) +// +// dkgTimeoutSeconds := 20 +// +// t.Log("waiting for initial set up to settle on all nodes") +// err = instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds) +// if err != nil { +// t.Fatal(err) +// } +// +// defer func() { +// for _, inst := range instances { +// _ = inst.stopAll() +// } +// }() +// +// t.Log("waiting for initial setup to finish") +// time.Sleep(5 * time.Second) +// +// // Stop beacon process... not the entire node +// err = instances[3].stop(beaconID) +// require.NoError(t, err) +// +// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") +// time.Sleep(10 * time.Second) +// +// // reload a different beacon +// err = instances[3].load("not-a-valid-beacon-name-here") +// require.Error(t, err) +// +// // test original beacon process status and hope it's still off +// testFailStatus(t, instances[3].ctrlPort, beaconID) +//} +// +//func TestDrandStatus_WithoutDKG(t *testing.T) { +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// allAddresses := make([]string, 0, n) +// for _, instance := range instances { +// allAddresses = append(allAddresses, instance.addr) +// } +// +// // check that each node can reach each other +// for i, instance := range instances { +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// remote = append(remote, allAddresses...) +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } +// } +// // stop one and check that all nodes report this node down +// toStop := 2 +// insToStop := instances[toStop] +// err := insToStop.stopAll() +// require.NoError(t, err) +// +// for i, instance := range instances { +// if i == toStop { +// continue +// } +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// remote = append(remote, allAddresses...) +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// if j != toStop { +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } else { +// require.Contains(t, buff.String(), instance.addr+" -> X") +// } +// } +// } +//} +// +//func TestDrandStatus_WithDKG_NoAddress(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping slow test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// +// for i, inst := range instances { +// if i == 0 { +// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) +// } else { +// inst.join(t, beaconID) +// } +// } +// instances[0].executeDKG(t, beaconID) +// +// dkgTimeoutSeconds := 20 +// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) +// t.Log("waiting for initial set up to settle on all nodes") +// +// // check that each node can reach each other +// for i, instance := range instances { +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } +// } +// // stop one and check that all nodes report this node down +// toStop := 2 +// insToStop := instances[toStop] +// err = insToStop.stopAll() +// require.NoError(t, err) +// +// for i, instance := range instances { +// if i == toStop { +// continue +// } +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// if j != toStop { +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } else { +// require.Contains(t, buff.String(), instance.addr+" -> X") +// } +// } +// } +//} +// +//func TestDrandStatus_WithDKG_OneAddress(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping slow test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// +// for i, inst := range instances { +// if i == 0 { +// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) +// } else { +// inst.join(t, beaconID) +// } +// } +// instances[0].executeDKG(t, beaconID) +// +// dkgTimeoutSeconds := 20 +// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) +// t.Log("waiting for initial set up to settle on all nodes") +// +// // check that each node can reach each other +// for i, instance := range instances { +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// remote = append(remote, instances[i].addr) +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } +// } +// // stop one and check that all nodes report this node down +// toStop := 2 +// insToStop := instances[toStop] +// err = insToStop.stopAll() +// require.NoError(t, err) +// +// for i, instance := range instances { +// if i == toStop { +// continue +// } +// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} +// remote = append(remote, instances[i].addr) +// var buff bytes.Buffer +// +// cli := CLI() +// cli.Writer = &buff +// +// err := cli.Run(remote) +// require.NoError(t, err) +// for j, instance := range instances { +// if i == j { +// continue +// } +// if j != toStop { +// require.Contains(t, buff.String(), instance.addr+" -> OK") +// } else { +// require.Contains(t, buff.String(), instance.addr+" -> X") +// } +// } +// } +//} +// +//func TestEmptyPortSelectionUsesDefaultDuringKeygen(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := t.TempDir() +// app := CLI() +// +// // args are missing a port for the node address +// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} +// // after being prompted for a port, the 'user' hits enter to select the default +// app.Reader = strings.NewReader("\n") +// +// require.NoError(t, app.Run(args)) +//} +// +//func TestValidPortSelectionSucceedsDuringKeygen(t *testing.T) { +// beaconID := test.GetBeaconIDFromEnv() +// +// tmp := t.TempDir() +// app := CLI() +// +// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} +// app.Reader = strings.NewReader("8080\n") +// +// require.NoError(t, app.Run(args)) +//} +// +//type drandInstance struct { +// path string +// ctrlPort string +// addr string +// metrics string +// certPath string +// keyPath string +// certsDir string +//} +// +//func (d *drandInstance) stopAll() error { +// return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort}) +//} +// +//func (d *drandInstance) stop(beaconID string) error { +// return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort, "--id", beaconID}) +//} +// +//func (d *drandInstance) startInitialDKG( +// t *testing.T, +// l log.Logger, +// instances []*drandInstance, +// threshold, +// //nolint:unparam // This is a parameter +// periodSeconds int, +// beaconID string, +// sch *crypto.Scheme, +//) { +// t.Helper() +// +// addrs := make([]string, len(instances)) +// for i, v := range instances { +// addrs[i] = v.ctrlPort +// } +// +// proposal, err := generateJoiningProposal(l, "default", addrs) +// require.NoError(t, err) +// +// proposalPath := filepath.Join(t.TempDir(), "proposal.toml") +// err = os.WriteFile(proposalPath, []byte(proposal), 0755) +// require.NoError(t, err) +// +// dkgArgs := []string{ +// "drand", +// "dkg", +// "propose", +// "--proposal", proposalPath, +// "--transition-time", fmt.Sprintf("%ds", 30*periodSeconds), +// "--catchup-period", fmt.Sprintf("%ds", periodSeconds/2), +// "--threshold", fmt.Sprintf("%d", threshold), +// "--period", fmt.Sprintf("%ds", periodSeconds), +// "--control", d.ctrlPort, +// "--scheme", sch.Name, +// "--id", beaconID, +// } +// +// err = CLI().Run(dkgArgs) +// require.NoError(t, err) +//} +// +//func (d *drandInstance) executeDKG(t *testing.T, beaconID string) { +// t.Helper() +// dkgArgs := []string{ +// "drand", +// "dkg", +// "execute", +// "--control", d.ctrlPort, +// "--id", beaconID, +// } +// +// err := CLI().Run(dkgArgs) +// require.NoError(t, err) +//} +// +//func (d *drandInstance) awaitDKGComplete( +// t *testing.T, +// beaconID string, +// //nolint:unparam // This is a parameter +// epoch uint32, +// timeoutSeconds int, +//) error { +// t.Helper() +// dkgArgs := []string{ +// "drand", +// "dkg", +// "status", +// "--control", d.ctrlPort, +// "--id", beaconID, +// "--format", "csv", +// } +// +// for i := 0; i < timeoutSeconds; i++ { +// cli := CLI() +// var buf bytes.Buffer +// cli.Writer = &buf +// +// err := cli.Run(dkgArgs) +// if err != nil { +// return err +// } +// +// statusOutput := buf.String() +// expected := fmt.Sprintf("State:Complete,Epoch:%d,", epoch) +// +// if strings.Contains(statusOutput, expected) { +// return nil +// } +// time.Sleep(1 * time.Second) +// } +// +// return errors.New("DKG didn't complete within the timeout") +//} +// +//func (d *drandInstance) load(beaconID string) error { +// reloadArgs := []string{ +// "drand", +// "load", +// "--control", d.ctrlPort, +// "--id", beaconID, +// } +// +// return CLI().Run(reloadArgs) +//} +// +//func (d *drandInstance) run(t *testing.T, beaconID string) { +// t.Helper() +// +// d.runWithStartArgs(t, beaconID, nil) +//} +// +//func (d *drandInstance) runWithStartArgs(t *testing.T, beaconID string, startArgs []string) { +// t.Helper() +// +// require.Equal(t, 0, len(startArgs)%2, "start args must be in pairs of option/value") +// +// baseArgs := []string{ +// "drand", +// "start", +// "--verbose", +// "--tls-cert", d.certPath, +// "--tls-key", d.keyPath, +// "--certs-dir", d.certsDir, +// "--control", d.ctrlPort, +// "--folder", d.path, +// "--metrics", d.metrics, +// "--private-listen", d.addr, +// } +// +// baseArgs = append(baseArgs, startArgs...) +// +// go func() { +// err := CLI().Run(baseArgs) +// require.NoError(t, err) +// }() +// +// // Prevent race condition in urfave/cli +// time.Sleep(100 * time.Millisecond) +// +// // make sure we run each one sequentially +// testStatus(t, d.ctrlPort, beaconID) +//} +// +//func (d *drandInstance) join(t *testing.T, id string) { +// t.Helper() +// joinArgs := []string{ +// "drand", +// "dkg", +// "join", +// "--id", +// id, +// "--control", +// d.ctrlPort, +// } +// +// err := CLI().Run(joinArgs) +// require.NoError(t, err) +//} +// +//func genAndLaunchDrandInstances(t *testing.T, n int) []*drandInstance { +// t.Helper() +// +// beaconID := test.GetBeaconIDFromEnv() +// +// ins := genDrandInstances(t, beaconID, n) +// return launchDrandInstances(t, beaconID, ins) +//} +// +//func genDrandInstances(t *testing.T, beaconID string, n int) []*drandInstance { +// t.Helper() +// +// tmpPath := t.TempDir() +// +// certsDir := path.Join(tmpPath, "certs") +// require.NoError(t, os.Mkdir(certsDir, 0o740)) +// l := testlogger.New(t) +// +// ins := make([]*drandInstance, 0, n) +// for i := 1; i <= n; i++ { +// nodePath, err := os.MkdirTemp(tmpPath, "node") +// require.NoError(t, err) +// +// certPath := path.Join(nodePath, "cert") +// keyPath := path.Join(nodePath, "tls.key") +// pubPath := path.Join(tmpPath, "pub.key") +// +// freePort := test.FreePort() +// addr := "127.0.0.1:" + freePort +// ctrlPort := test.FreePort() +// metricsPort := test.FreePort() +// +// // generate key so it loads +// // TODO let's remove this requirement - no need for longterm keys +// priv, err := key.NewTLSKeyPair(addr, nil) +// require.NoError(t, err) +// require.NoError(t, key.Save(pubPath, priv.Public, false)) +// config := core.NewConfig(l, core.WithConfigFolder(nodePath)) +// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) +// err = fileStore.SaveKeyPair(priv) +// require.NoError(t, err) +// +// h, _, err := gnet.SplitHostPort(addr) +// require.NoError(t, err) +// +// err = httpscerts.Generate(certPath, keyPath, h) +// require.NoError(t, err) +// +// // copy into one folder for giving a common CERT folder +// _, err = exec.Command("cp", certPath, path.Join(certsDir, fmt.Sprintf("cert-%d", i))).Output() +// require.NoError(t, err) +// +// ins = append(ins, &drandInstance{ +// addr: addr, +// ctrlPort: ctrlPort, +// path: nodePath, +// keyPath: keyPath, +// metrics: metricsPort, +// certPath: certPath, +// certsDir: certsDir, +// }) +// } +// +// return ins +//} +// +//func launchDrandInstances(t *testing.T, beaconID string, ins []*drandInstance) []*drandInstance { +// t.Helper() +// +// for _, instance := range ins { +// instance.run(t, beaconID) +// } +// return ins +//} +// +////nolint:funlen // This is a test +//func TestMemDBBeaconReJoinsNetworkAfterLongStop(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// // How many rounds to generate while the node is stopped. +// roundsWhileMissing := 50 +// period := 1 +// n := 4 +// instances := genDrandInstances(t, beaconID, n) +// memDBNodeID := len(instances) - 1 +// +// for i := 0; i < memDBNodeID; i++ { +// inst := instances[i] +// inst.run(t, beaconID) +// } +// +// instances[memDBNodeID].runWithStartArgs(t, beaconID, []string{"--db", "memdb"}) +// memDBNode := instances[memDBNodeID] +// +// for i, inst := range instances { +// inst := inst +// if i == 0 { +// inst.startInitialDKG(t, l, instances, 3, period, beaconID, sch) +// // Wait a bit after launching the leader to launch the other nodes too. +// time.Sleep(500 * time.Millisecond) +// } else { +// inst.join(t, beaconID) +// } +// } +// +// instances[0].executeDKG(t, beaconID) +// +// t.Log("waiting for initial set up to settle on all nodes") +// err = instances[0].awaitDKGComplete(t, beaconID, 1, 60) +// require.NoError(t, err) +// +// defer func() { +// for _, inst := range instances { +// // We want to ignore this error, at least until the stop command won't return an error +// // when correctly running the stop command. +// t.Logf("stopping instance %v\n", inst.addr) +// err := inst.stopAll() +// require.NoError(t, err) +// t.Logf("stopped instance %v\n", inst.addr) +// } +// }() +// +// memDBClient, err := net.NewControlClient(l, memDBNode.ctrlPort) +// require.NoError(t, err) +// +// chainInfo, err := memDBClient.ChainInfo(beaconID) +// require.NoError(t, err) +// +// // Wait until DKG finishes +// secondsToGenesisTime := chainInfo.GenesisTime - time.Now().Unix() +// t.Logf("waiting %ds until DKG finishes\n", secondsToGenesisTime) +// time.Sleep(time.Duration(secondsToGenesisTime) * time.Second) +// +// // Wait for some rounds to be generated +// t.Log("wait for some rounds to be generated") +// time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) +// +// // Get the status before stopping the node +// status, err := memDBClient.Status(beaconID) +// require.NoError(t, err) +// +// require.False(t, status.ChainStore.IsEmpty) +// require.NotZero(t, status.ChainStore.LastRound) +// +// lastRoundBeforeShutdown := status.ChainStore.LastRound +// +// // Stop beacon process... not the entire node +// err = instances[memDBNodeID].stop(beaconID) +// require.NoError(t, err) +// +// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") +// time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) +// +// // reload a beacon +// err = instances[memDBNodeID].load(beaconID) +// require.NoError(t, err) +// +// // Wait a bit to allow the node to startup and load correctly +// time.Sleep(2 * time.Second) +// +// status, err = memDBClient.Status(beaconID) +// require.NoError(t, err) +// +// require.False(t, status.ChainStore.IsEmpty) +// require.NotZero(t, status.ChainStore.LastRound) +// expectedRound := lastRoundBeforeShutdown + uint64(roundsWhileMissing) +// t.Logf("comparing lastRound %d with lastRoundBeforeShutdown %d\n", status.ChainStore.LastRound, expectedRound) +// require.GreaterOrEqual(t, status.ChainStore.LastRound, expectedRound) +//} +// +//func TestDKGStatusDoesntBlowUp(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping test in short mode.") +// } +// +// l := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// beaconID := test.GetBeaconIDFromEnv() +// +// // start some nodes +// n := 4 +// instances := genAndLaunchDrandInstances(t, n) +// +// // execute a DKG +// for i, inst := range instances { +// if i == 0 { +// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) +// } else { +// inst.join(t, beaconID) +// } +// } +// instances[0].executeDKG(t, beaconID) +// +// // wait for the DKG to finish +// dkgTimeoutSeconds := 20 +// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) +// t.Log("waiting for initial set up to settle on all nodes") +// +// // check the status command runs fine +// err = CLI().Run([]string{"drand", "dkg", "status", "--control", instances[0].ctrlPort}) +// require.NoError(t, err) +//} diff --git a/internal/control.go b/internal/control.go deleted file mode 100644 index 5859048..0000000 --- a/internal/control.go +++ /dev/null @@ -1,39 +0,0 @@ -package drand - -import ( - "fmt" - "github.com/drand/drand/common/log" - json "github.com/nikkolasg/hexjson" - "github.com/urfave/cli/v2" - "io" -) - -func schemesCmd(c *cli.Context, l log.Logger) error { - client, err := controlClient(c, l) - if err != nil { - return err - } - - resp, err := client.ListSchemes() - if err != nil { - return fmt.Errorf("drand: can't get the list of scheme ids availables ... %w", err) - } - - fmt.Fprintf(c.App.Writer, "Drand supports the following list of schemes: \n") - - for i, id := range resp.Ids { - fmt.Fprintf(c.App.Writer, "%d) %s \n", i, id) - } - - fmt.Fprintf(c.App.Writer, "\nChoose one of them and set it on --%s flag \n", schemeFlag.Name) - return nil -} - -func printJSON(w io.Writer, j interface{}) error { - buff, err := json.MarshalIndent(j, "", " ") - if err != nil { - return fmt.Errorf("could not JSON marshal: %w", err) - } - fmt.Fprintln(w, string(buff)) - return nil -} diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 4e774ee..7459b33 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -1,170 +1,170 @@ package lib -import ( - "bytes" - "context" - "encoding/hex" - "errors" - "os" - "path/filepath" - "runtime" - "testing" - "time" - - clock "github.com/jonboulle/clockwork" - "github.com/stretchr/testify/require" - "github.com/urfave/cli/v2" - - "github.com/drand/drand-cli/internal/test/mock" - "github.com/drand/drand-cli/internal/test/testlogger" - client2 "github.com/drand/drand/client" - httpmock "github.com/drand/drand/client/test/http/mock" - commonutils "github.com/drand/drand/common" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" -) - -var ( - opts []client2.Option -) - -const ( - fakeGossipRelayAddr = "/ip4/8.8.8.8/tcp/9/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" - fakeChainHash = "6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83" -) - -func mockAction(c *cli.Context) error { - _, err := Create(c, false, opts...) - return err -} - -func run(l log.Logger, args []string) error { - app := cli.NewApp() - app.Name = "mock-client" - app.Flags = ClientFlags - app.Action = func(c *cli.Context) error { - c.Context = log.ToContext(c.Context, l) - return mockAction(c) - } - - return app.Run(args) -} - -func TestClientLib(t *testing.T) { - opts = []client2.Option{} - lg := testlogger.New(t) - err := run(lg, []string{"mock-client"}) - if err == nil { - t.Fatal("need to specify a connection method.", err) - } - - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - clk := clock.NewFakeClockAt(time.Now()) - addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) - defer cancel() - - grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) - go grpcLis.Start() - defer grpcLis.Stop(context.Background()) - - args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} - err = run(lg, args) - if err != nil { - t.Fatal("GRPC should work", err) - } - - args = []string{"mock-client", "--url", "https://" + addr} - err = run(lg, args) - if err == nil { - t.Fatal("http needs insecure or hash", err) - } - - args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} - err = run(lg, args) - if err != nil { - t.Fatal("http should construct", err) - } - - args = []string{"mock-client", "--relay", fakeGossipRelayAddr} - err = run(lg, args) - if err == nil { - t.Fatal("relays need URL to get chain info and hash", err) - } - - args = []string{"mock-client", "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} - err = run(lg, args) - if err == nil { - t.Fatal("relays need URL to get chain info and hash", err) - } - - args = []string{"mock-client", "--url", "http://" + addr, "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} - err = run(lg, args) - if err != nil { - t.Fatal("unable to get relay to work", err) - } -} - -func TestClientLibGroupConfTOML(t *testing.T) { - lg := testlogger.New(t) - err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) - if err != nil { - t.Fatal(err) - } -} - -func TestClientLibGroupConfJSON(t *testing.T) { - lg := testlogger.New(t) - sch, err := crypto.GetSchemeFromEnv() - require.NoError(t, err) - clk := clock.NewFakeClockAt(time.Now()) - addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) - defer cancel() - - var b bytes.Buffer - require.NoError(t, info.ToJSON(&b, nil)) - - infoPath := filepath.Join(t.TempDir(), "info.json") - - err = os.WriteFile(infoPath, b.Bytes(), 0644) - if err != nil { - t.Fatal(err) - } - - err = run(lg, []string{"mock-client", "--url", "http://" + addr, "--group-conf", infoPath}) - if err != nil { - t.Fatal(err) - } -} - -func TestClientLibChainHashOverrideError(t *testing.T) { - lg := testlogger.New(t) - err := run(lg, []string{ - "mock-client", - "--relay", - fakeGossipRelayAddr, - "--group-conf", - groupTOMLPath(), - "--hash", - fakeChainHash, - }) - if !errors.Is(err, commonutils.ErrInvalidChainHash) { - t.Fatal("expected error from mismatched chain hashes. Got: ", err) - } -} - -func TestClientLibListenPort(t *testing.T) { - lg := testlogger.New(t) - err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) - if err != nil { - t.Fatal(err) - } -} - -func groupTOMLPath() string { - _, file, _, ok := runtime.Caller(0) - if !ok { - return "" - } - return filepath.Join(filepath.Dir(file), "..", "..", "internal", "test", "default.toml") -} +//import ( +// "bytes" +// "context" +// "encoding/hex" +// "errors" +// "os" +// "path/filepath" +// "runtime" +// "testing" +// "time" +// +// clock "github.com/jonboulle/clockwork" +// "github.com/stretchr/testify/require" +// "github.com/urfave/cli/v2" +// +// "github.com/drand/drand-cli/internal/test/mock" +// "github.com/drand/drand-cli/internal/test/testlogger" +// client2 "github.com/drand/drand/client" +// httpmock "github.com/drand/drand/client/test/http/mock" +// commonutils "github.com/drand/drand/common" +// "github.com/drand/drand/common/log" +// "github.com/drand/drand/crypto" +//) +// +//var ( +// opts []client2.Option +//) +// +//const ( +// fakeGossipRelayAddr = "/ip4/8.8.8.8/tcp/9/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" +// fakeChainHash = "6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83" +//) +// +//func mockAction(c *cli.Context) error { +// _, err := Create(c, false, opts...) +// return err +//} +// +//func run(l log.Logger, args []string) error { +// app := cli.NewApp() +// app.Name = "mock-client" +// app.Flags = ClientFlags +// app.Action = func(c *cli.Context) error { +// c.Context = log.ToContext(c.Context, l) +// return mockAction(c) +// } +// +// return app.Run(args) +//} +// +//func TestClientLib(t *testing.T) { +// opts = []client2.Option{} +// lg := testlogger.New(t) +// err := run(lg, []string{"mock-client"}) +// if err == nil { +// t.Fatal("need to specify a connection method.", err) +// } +// +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// clk := clock.NewFakeClockAt(time.Now()) +// addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) +// defer cancel() +// +// grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) +// go grpcLis.Start() +// defer grpcLis.Stop(context.Background()) +// +// args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} +// err = run(lg, args) +// if err != nil { +// t.Fatal("GRPC should work", err) +// } +// +// args = []string{"mock-client", "--url", "https://" + addr} +// err = run(lg, args) +// if err == nil { +// t.Fatal("http needs insecure or hash", err) +// } +// +// args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} +// err = run(lg, args) +// if err != nil { +// t.Fatal("http should construct", err) +// } +// +// args = []string{"mock-client", "--relay", fakeGossipRelayAddr} +// err = run(lg, args) +// if err == nil { +// t.Fatal("relays need URL to get chain info and hash", err) +// } +// +// args = []string{"mock-client", "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} +// err = run(lg, args) +// if err == nil { +// t.Fatal("relays need URL to get chain info and hash", err) +// } +// +// args = []string{"mock-client", "--url", "http://" + addr, "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} +// err = run(lg, args) +// if err != nil { +// t.Fatal("unable to get relay to work", err) +// } +//} +// +//func TestClientLibGroupConfTOML(t *testing.T) { +// lg := testlogger.New(t) +// err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) +// if err != nil { +// t.Fatal(err) +// } +//} +// +//func TestClientLibGroupConfJSON(t *testing.T) { +// lg := testlogger.New(t) +// sch, err := crypto.GetSchemeFromEnv() +// require.NoError(t, err) +// clk := clock.NewFakeClockAt(time.Now()) +// addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) +// defer cancel() +// +// var b bytes.Buffer +// require.NoError(t, info.ToJSON(&b, nil)) +// +// infoPath := filepath.Join(t.TempDir(), "info.json") +// +// err = os.WriteFile(infoPath, b.Bytes(), 0644) +// if err != nil { +// t.Fatal(err) +// } +// +// err = run(lg, []string{"mock-client", "--url", "http://" + addr, "--group-conf", infoPath}) +// if err != nil { +// t.Fatal(err) +// } +//} +// +//func TestClientLibChainHashOverrideError(t *testing.T) { +// lg := testlogger.New(t) +// err := run(lg, []string{ +// "mock-client", +// "--relay", +// fakeGossipRelayAddr, +// "--group-conf", +// groupTOMLPath(), +// "--hash", +// fakeChainHash, +// }) +// if !errors.Is(err, commonutils.ErrInvalidChainHash) { +// t.Fatal("expected error from mismatched chain hashes. Got: ", err) +// } +//} +// +//func TestClientLibListenPort(t *testing.T) { +// lg := testlogger.New(t) +// err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) +// if err != nil { +// t.Fatal(err) +// } +//} +// +//func groupTOMLPath() string { +// _, file, _, ok := runtime.Caller(0) +// if !ok { +// return "" +// } +// return filepath.Join(filepath.Dir(file), "..", "..", "internal", "test", "default.toml") +//} diff --git a/internal/proposal_file.go b/internal/proposal_file.go deleted file mode 100644 index 64356b8..0000000 --- a/internal/proposal_file.go +++ /dev/null @@ -1,124 +0,0 @@ -package drand - -import ( - "encoding/hex" - - "github.com/BurntSushi/toml" - - "github.com/drand/drand/protobuf/drand" -) - -type ProposalFileFormat struct { - Joining []*TomlParticipant - Leaving []*TomlParticipant - Remaining []*TomlParticipant -} - -type ProposalFile struct { - Joining []*drand.Participant - Leaving []*drand.Participant - Remaining []*drand.Participant -} - -func ParseProposalFile(filepath string) (*ProposalFile, error) { - proposalFile := ProposalFileFormat{} - _, err := toml.DecodeFile(filepath, &proposalFile) - - if err != nil { - return nil, err - } - - return &ProposalFile{ - Joining: proposalFile.Joiners(), - Leaving: proposalFile.Leavers(), - Remaining: proposalFile.Remainers(), - }, nil -} - -func (p *ProposalFileFormat) Joiners() []*drand.Participant { - out := make([]*drand.Participant, len(p.Joining)) - - for i, participant := range p.Joining { - out[i] = participant.Into() - } - - return out -} -func (p *ProposalFileFormat) Leavers() []*drand.Participant { - out := make([]*drand.Participant, len(p.Leaving)) - - for i, participant := range p.Leaving { - out[i] = participant.Into() - } - - return out -} - -func (p *ProposalFileFormat) Remainers() []*drand.Participant { - out := make([]*drand.Participant, len(p.Remaining)) - - for i, participant := range p.Remaining { - out[i] = participant.Into() - } - - return out -} - -type TomlParticipant struct { - Address string - TLS bool - Key string - Signature string -} - -func (t *TomlParticipant) Into() *drand.Participant { - return &drand.Participant{ - Address: t.Address, - Tls: t.TLS, - Key: decodeHexOrPanic(t.Key), - Signature: decodeHexOrPanic(t.Signature), - } -} - -func (p *ProposalFile) TOML() ProposalFileFormat { - out := ProposalFileFormat{} - - for _, j := range p.Joining { - p := encode(j) - out.Joining = append(out.Joining, &p) - } - - for _, r := range p.Remaining { - p := encode(r) - out.Remaining = append(out.Remaining, &p) - } - - for _, l := range p.Leaving { - p := encode(l) - out.Leaving = append(out.Leaving, &p) - } - - return out -} - -func encode(p *drand.Participant) TomlParticipant { - return TomlParticipant{ - Address: p.Address, - TLS: p.Tls, - Key: hex.EncodeToString(p.Key), - Signature: hex.EncodeToString(p.Signature), - } -} - -func decodeHexOrPanic(input string) []byte { - // input lengths are u8 instead of hex, so /2 - byteLength := len(input) / 2 - out := make([]byte, byteLength) - - _, err := hex.Decode(out, []byte(input)) - if err != nil { - panic("Invalid hex in proposal file!") - } - - return out -} diff --git a/internal/proposal_file_test.go b/internal/proposal_file_test.go deleted file mode 100644 index 9f8c3be..0000000 --- a/internal/proposal_file_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package drand - -import ( - "bytes" - "encoding/hex" - "errors" - - "github.com/BurntSushi/toml" - - "github.com/drand/drand-cli/internal/net" - "github.com/drand/drand/common/log" -) - -func generateJoiningProposal(l log.Logger, beaconID string, joining []string) (string, error) { - return generateProposal(l, beaconID, joining, []string{}, []string{}) -} - -func generateProposal(l log.Logger, beaconID string, joining, remaining, leaving []string) (string, error) { - if len(joining) == 0 && len(remaining) == 0 && len(leaving) == 0 { - return "", errors.New("you must fill at least one of the ") - } - - extractParticipants := func(addrs []string) ([]*TomlParticipant, error) { - var participants []*TomlParticipant - for _, addr := range addrs { - client, err := net.NewControlClient(l, addr) - if err != nil { - return nil, err - } - res, err := client.PublicKey(beaconID) - if err != nil { - return nil, err - } - participants = append(participants, &TomlParticipant{ - Address: res.Addr, - Key: hex.EncodeToString(res.PubKey), - Signature: hex.EncodeToString(res.Signature), - }) - } - return participants, nil - } - - joiners, err := extractParticipants(joining) - if err != nil { - return "", err - } - remainers, err := extractParticipants(remaining) - if err != nil { - return "", err - } - leavers, err := extractParticipants(leaving) - if err != nil { - return "", err - } - - outputFile := ProposalFileFormat{ - Joining: joiners, - Leaving: leavers, - Remaining: remainers, - } - - b := bytes.NewBufferString("") - err = toml.NewEncoder(b).Encode(outputFile) - if err != nil { - return "", err - } - - return b.String(), nil -} diff --git a/main.go b/main.go index d04cbfb..e41ebed 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/drand/drand-cli/internal/drand" + drand "github.com/drand/drand-cli/internal" ) func main() { From 16caf31d3694831caf69d6e0729b5e2a159a698c Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Wed, 6 Sep 2023 13:29:27 +0200 Subject: [PATCH 05/28] Only tests to fix now --- client/http/http_test.go | 183 +++++++++-------- go.mod | 55 ++++-- go.sum | 179 ++++++++++++++--- gossip-relay/.gitignore | 4 + gossip-relay/README.md | 335 ++++++++++++++++++++++++++++++++ gossip-relay/main.go | 238 +++++++++++++++++++++++ http-relay/main.go | 209 ++++++++++++++++++++ internal/cli_test.go | 27 +-- internal/lib/cli.go | 244 +++++++++++++++++++++++ internal/lib/cli_test.go | 230 +++++++++++----------- internal/lp2p/addrutil.go | 77 ++++++++ internal/lp2p/addrutil_test.go | 109 +++++++++++ internal/lp2p/ctor.go | 171 ++++++++++++++++ internal/lp2p/ctor_test.go | 54 +++++ internal/lp2p/relaynode.go | 186 ++++++++++++++++++ internal/lp2p/relaynode_test.go | 120 ++++++++++++ internal/net/client.go | 16 ++ s3-relay/README.md | 50 +++++ s3-relay/main.go | 204 +++++++++++++++++++ 19 files changed, 2408 insertions(+), 283 deletions(-) create mode 100644 gossip-relay/.gitignore create mode 100644 gossip-relay/README.md create mode 100644 gossip-relay/main.go create mode 100644 http-relay/main.go create mode 100644 internal/lib/cli.go create mode 100644 internal/lp2p/addrutil.go create mode 100644 internal/lp2p/addrutil_test.go create mode 100644 internal/lp2p/ctor.go create mode 100644 internal/lp2p/ctor_test.go create mode 100644 internal/lp2p/relaynode.go create mode 100644 internal/lp2p/relaynode_test.go create mode 100644 internal/net/client.go create mode 100644 s3-relay/README.md create mode 100644 s3-relay/main.go diff --git a/client/http/http_test.go b/client/http/http_test.go index f18092b..b2b95bb 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -2,12 +2,7 @@ package http import ( "context" - "encoding/json" "errors" - "fmt" - "github.com/drand/drand/common/log" - "github.com/drand/drand/protobuf/drand" - "net" "net/http" "sync" "testing" @@ -99,7 +94,7 @@ func TestHTTPGetLatest(t *testing.T) { t.Fatal(err) } - if r1.Round() != r0.Round()+1 { + if r1.GetRound() != r0.GetRound()+1 { t.Fatal("expected round progression") } _ = httpClient.Close() @@ -157,7 +152,7 @@ func TestHTTPWatch(t *testing.T) { if !ok { t.Fatal("should get a result from watching") } - if len(first.Randomness()) == 0 { + if len(first.GetRandomness()) == 0 { t.Fatal("should get randomness from watching") } @@ -188,7 +183,7 @@ func TestHTTPClientClose(t *testing.T) { if err != nil { t.Fatal(err) } - if result.Round() != 1969 { + if result.GetRound() != 1969 { t.Fatal("unexpected round.") } @@ -214,90 +209,88 @@ func TestHTTPClientClose(t *testing.T) { } //nolint:funlen -func TestHTTPRelay(t *testing.T) { - lg := testlogger.New(t) - ctx := log.ToContext(context.Background(), lg) - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - test.Tracer(t, ctx) - - clk := clock.NewFakeClockAt(time.Now()) - c, _ := withClient(t, clk) - - handler, err := New(ctx, "") - if err != nil { - t.Fatal(err) - } - - info, err := c.Info(ctx) - if err != nil { - t.Fatal(err) - } - - handler.RegisterNewBeaconHandler(c, info.HashString()) - - listener, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - server := http.Server{Handler: handler.GetHTTPHandler()} - go func() { _ = server.Serve(listener) }() - defer func() { _ = server.Shutdown(ctx) }() - - err = nhttp.IsServerReady(ctx, listener.Addr().String()) - if err != nil { - t.Fatal(err) - } - - getChains := fmt.Sprintf("http://%s/chains", listener.Addr().String()) - resp := getWithCtx(ctx, getChains, t) - if resp.StatusCode != http.StatusOK { - t.Error("expected http status code 200") - } - var chains []string - require.NoError(t, json.NewDecoder(resp.Body).Decode(&chains)) - require.NoError(t, resp.Body.Close()) - - if len(chains) != 1 { - t.Error("expected chain hash qty not valid") - } - if chains[0] != info.HashString() { - t.Error("expected chain hash not valid") - } - - getChain := fmt.Sprintf("http://%s/%s/info", listener.Addr().String(), info.HashString()) - resp = getWithCtx(ctx, getChain, t) - cip := new(drand.ChainInfoPacket) - require.NoError(t, json.NewDecoder(resp.Body).Decode(cip)) - require.NotNil(t, cip.Hash) - require.NotNil(t, cip.PublicKey) - require.NoError(t, resp.Body.Close()) - - // Test exported interfaces. - u := fmt.Sprintf("http://%s/%s/public/2", listener.Addr().String(), info.HashString()) - resp = getWithCtx(ctx, u, t) - body := make(map[string]interface{}) - require.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) - require.NoError(t, resp.Body.Close()) - - if _, ok := body["signature"]; !ok { - t.Fatal("expected signature in random response.") - } - - u = fmt.Sprintf("http://%s/%s/public/latest", listener.Addr().String(), info.HashString()) - resp, err = http.Get(u) - if err != nil { - t.Fatal(err) - } - body = make(map[string]interface{}) - - if err = json.NewDecoder(resp.Body).Decode(&body); err != nil { - t.Fatal(err) - } - require.NoError(t, resp.Body.Close()) - - if _, ok := body["round"]; !ok { - t.Fatal("expected signature in latest response.") - } -} +//func TestHTTPRelay(t *testing.T) { +// lg := testlogger.New(t) +// ctx := log.ToContext(context.Background(), lg) +// ctx, cancel := context.WithCancel(ctx) +// defer cancel() +// +// clk := clock.NewFakeClockAt(time.Now()) +// c, _ := withClient(t, clk) +// +// handler, err := dhandler.New(ctx, "") +// if err != nil { +// t.Fatal(err) +// } +// +// info, err := c.Info(ctx) +// if err != nil { +// t.Fatal(err) +// } +// +// handler.RegisterNewBeaconHandler(c, info.HashString()) +// +// listener, err := net.Listen("tcp", "127.0.0.1:0") +// if err != nil { +// t.Fatal(err) +// } +// server := http.Server{Handler: handler.GetHTTPHandler()} +// go func() { _ = server.Serve(listener) }() +// defer func() { _ = server.Shutdown(ctx) }() +// +// err = nhttp.IsServerReady(ctx, listener.Addr().String()) +// if err != nil { +// t.Fatal(err) +// } +// +// getChains := fmt.Sprintf("http://%s/chains", listener.Addr().String()) +// resp := getWithCtx(ctx, getChains, t) +// if resp.StatusCode != http.StatusOK { +// t.Error("expected http status code 200") +// } +// var chains []string +// require.NoError(t, json.NewDecoder(resp.Body).Decode(&chains)) +// require.NoError(t, resp.Body.Close()) +// +// if len(chains) != 1 { +// t.Error("expected chain hash qty not valid") +// } +// if chains[0] != info.HashString() { +// t.Error("expected chain hash not valid") +// } +// +// getChain := fmt.Sprintf("http://%s/%s/info", listener.Addr().String(), info.HashString()) +// resp = getWithCtx(ctx, getChain, t) +// cip := new(drand.ChainInfoPacket) +// require.NoError(t, json.NewDecoder(resp.Body).Decode(cip)) +// require.NotNil(t, cip.Hash) +// require.NotNil(t, cip.PublicKey) +// require.NoError(t, resp.Body.Close()) +// +// // Test exported interfaces. +// u := fmt.Sprintf("http://%s/%s/public/2", listener.Addr().String(), info.HashString()) +// resp = getWithCtx(ctx, u, t) +// body := make(map[string]interface{}) +// require.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) +// require.NoError(t, resp.Body.Close()) +// +// if _, ok := body["signature"]; !ok { +// t.Fatal("expected signature in random response.") +// } +// +// u = fmt.Sprintf("http://%s/%s/public/latest", listener.Addr().String(), info.HashString()) +// resp, err = http.Get(u) +// if err != nil { +// t.Fatal(err) +// } +// body = make(map[string]interface{}) +// +// if err = json.NewDecoder(resp.Body).Decode(&body); err != nil { +// t.Fatal(err) +// } +// require.NoError(t, resp.Body.Close()) +// +// if _, ok := body["round"]; !ok { +// t.Fatal("expected signature in latest response.") +// } +//} diff --git a/go.mod b/go.mod index 1dc92da..5452ccf 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,27 @@ go 1.20 replace github.com/drand/drand => ../drand require ( - github.com/drand/drand v0.0.0-00010101000000-000000000000 + github.com/aws/aws-sdk-go v1.45.3 + github.com/drand/drand v1.5.7 github.com/drand/kyber v1.2.0 + github.com/google/uuid v1.3.1 + github.com/gorilla/handlers v1.5.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 + github.com/ipfs/go-datastore v0.6.0 + github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 - github.com/libp2p/go-libp2p v0.30.0 + github.com/libp2p/go-libp2p v0.31.0 github.com/libp2p/go-libp2p-pubsub v0.9.3 github.com/multiformats/go-multiaddr v0.11.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.16.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.25.7 + golang.org/x/crypto v0.13.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 google.golang.org/protobuf v1.31.0 ) @@ -24,6 +33,7 @@ require ( github.com/BurntSushi/toml v1.3.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // 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 github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -31,26 +41,39 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/drand/kyber-bls12381 v0.3.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.2 // 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-chi/chi v1.5.4 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect + github.com/google/pprof v0.0.0-20230901174712-0191c66da455 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/hashicorp/golang-lru/arc/v2 v2.0.6 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/go-cid v0.4.1 // 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/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect @@ -74,29 +97,29 @@ require ( 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-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.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.11.0 // indirect + github.com/onsi/ginkgo/v2 v2.12.0 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.2 // indirect - github.com/quic-go/quic-go v0.37.6 // indirect + github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/quic-go/quic-go v0.38.1 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 // indirect + go.opentelemetry.io/otel v1.17.0 // indirect go.opentelemetry.io/otel/metric v1.17.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect go.uber.org/dig v1.17.0 // indirect @@ -104,15 +127,13 @@ require ( go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.13.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.57.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/go.sum b/go.sum index ee2248c..e8820df 100644 --- a/go.sum +++ b/go.sum @@ -7,11 +7,18 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-sdk-go v1.45.3 h1:Q8BksXg2ZUu2dCbA62+UCEtfvqsW8EO4tzt2IVeYAws= +github.com/aws/aws-sdk-go v1.45.3/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -22,6 +29,9 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= @@ -29,10 +39,14 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -45,6 +59,16 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= +github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -53,9 +77,14 @@ github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xt github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -64,9 +93,14 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD 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/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= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -78,6 +112,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 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= @@ -88,6 +124,10 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -99,11 +139,17 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= -github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20230901174712-0191c66da455 h1:YhRUmI1ttDC4sxKY2V62BTI8hCXnyZBV9h38eAanInE= +github.com/google/pprof v0.0.0-20230901174712-0191c66da455/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +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.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= 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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -119,21 +165,41 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/hashicorp/golang-lru/arc/v2 v2.0.6 h1:4NU7uP5vSoK6TbaMj3NtY478TTAWLso/vL1gpNrInHg= +github.com/hashicorp/golang-lru/arc/v2 v2.0.6/go.mod h1:cfdDIX05DWvYV6/shsxDfa/OVcRieOt+q4FnM8x+Xno= +github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= +github.com/hashicorp/golang-lru/v2 v2.0.6/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.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= +github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg= +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/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= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= @@ -144,6 +210,7 @@ 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= @@ -151,6 +218,7 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY 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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -164,8 +232,8 @@ 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.30.0 h1:9EZwFtJPFBcs/yJTnP90TpN1hgrT/EsFfM+OZuwV87U= -github.com/libp2p/go-libp2p v0.30.0/go.mod h1:nr2g5V7lfftwgiJ78/HrID+pwvayLyqKCEirT2Y3Byg= +github.com/libp2p/go-libp2p v0.31.0 h1:LFShhP8F6xthWiBBq3euxbKjZsoRajVEyBS9snfHxYg= +github.com/libp2p/go-libp2p v0.31.0/go.mod h1:W/FEK1c/t04PbRH3fA9i5oucu5YcgrG0JVoBWT1B7Eg= 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.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= @@ -182,6 +250,7 @@ github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8S github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= 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/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= @@ -205,6 +274,8 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8Rv github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +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-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -231,6 +302,8 @@ github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7B github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 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-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= 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= @@ -238,15 +311,16 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= 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.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= +github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -266,14 +340,15 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= 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-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= -github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.37.6 h1:2IIUmQzT5YNxAiaPGjs++Z4hGOtIR0q79uS5qE9ccfY= -github.com/quic-go/quic-go v0.37.6/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU= +github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= +github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE= +github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= github.com/quic-go/webtransport-go v0.5.3/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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= 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= @@ -306,9 +381,17 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 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/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= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -316,22 +399,29 @@ 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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= 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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 h1:HKORGpiOY0R0nAPtKx/ub8/7XoHhRooP8yNRkuPfelI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0/go.mod h1:e+y1M74SYXo/FcIx3UATwth2+5dDkM8dBi7eXg1tbw8= go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= @@ -341,6 +431,7 @@ go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiM go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= @@ -350,36 +441,43 @@ go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -398,8 +496,10 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -413,15 +513,18 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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-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-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-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -431,17 +534,27 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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-20220722155257-8c9f86f7a55f/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -451,14 +564,18 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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= @@ -477,8 +594,8 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= 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= @@ -491,12 +608,15 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -505,6 +625,7 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd 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.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/gossip-relay/.gitignore b/gossip-relay/.gitignore new file mode 100644 index 0000000..4208a2c --- /dev/null +++ b/gossip-relay/.gitignore @@ -0,0 +1,4 @@ +./relay-gossip +datastore +identity.key +relay-gossip diff --git a/gossip-relay/README.md b/gossip-relay/README.md new file mode 100644 index 0000000..a9468b7 --- /dev/null +++ b/gossip-relay/README.md @@ -0,0 +1,335 @@ + + +## Table of Contents + +- [Drand Pubsub Relay](#drand-pubsub-relay) + - [Install](#install) + - [Usage](#usage) + - [Relay gRPC](#relay-grpc) + - [Relay HTTP](#relay-http) + - [Relay Gossipsub](#relay-gossipsub) + - [Other options](#other-options) + - [Bootstrap peers](#bootstrap-peers) + - [Failover](#failover) + - [Configuring the libp2p pubsub node](#configuring-the-libp2p-pubsub-node) + - [Usage from a golang drand client](#usage-from-a-golang-drand-client) + - [With Group TOML or Chain Info](#with-group-toml-or-chain-info) + - [With Known Chain Hash](#with-known-chain-hash) + - [Insecurely](#insecurely) + + + +# Drand Pubsub Relay + +A program that relays drand randomness rounds over libp2p pubsub (gossipsub) from a gRPC, HTTP, or gossipsub source (labeled as _drand gossipsub relay_ in this diagram): + +``` + +-------------------------------+ + | | + | drand server | + | | + +-------------------------------+ + | gRPC API |--| HTTP API | + +------^-+------------^-+-------+ + | | | | + | | | | + | | | | + +--+-v------------+-v---+ + | drand gossipsub relay | + +----------+------------+ + | + | +Publish topic=/drand/pubsub/v0.0.0/ data={randomness} + | + | + +-----------v--------------+ + | | + | libp2p gossipsub network | + | | + +--+--------------------+--+ + | | + | | + Subscribe topic=/drand/pubsub/v0.0.0/ + | | + | | + +----------------v--------+ +-------v-----------------+ + | drand client WithPubsub | | drand client WithPubsub | + +-------------------------+ +-------------------------+ +``` + +## Install + +```sh +# Clone this repo +git clone https://github.com/drand/drand-cli.git +cd drand +# Build the executable +make relay-gossip-relay +# Outputs a `drand-relay-gossip-relay` executable to the current directory. +``` + +## Usage + +In general, you _should_ specify either a `-hash-list` or `-group-conf-list` flag in order for your client to validate the randomness it receives is from the correct chain. + +_Note_: You can provide multiple values to both `-hash-list` and`-group-conf-list` flags to support multiple beacons. + +### Relay gRPC + +```sh +drand-relay-gossip-relay run -grpc-connect=127.0.0.1:3000 \ + -cert=/path/to/grpc-drand-cert +``` + +If you do not have gRPC transport credentials, you can use the `-insecure` flag: + +```sh +drand-relay-gossip-relay run -grpc-connect=127.0.0.1:3000 \ + -insecure +``` + +Or, with a hashlist: +```shell + drand-relay-gossip-relay run -grpc-connect=127.0.0.1:3000 \ + -insecure \ + -hash-list=6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83,dbd506d6ef76e5f386f41c651dcb808c5bcbd75471cc4eafa3f4df7ad4e4c493 +``` + +### Relay HTTP + +The gossip relay can also relay directly from an HTTP API. You can specify multiple endpoints to enable failover. + +```sh +drand-relay-gossip-relay run -url=https://api.drand.sh \ + -url=https://api2.drand.sh \ + -hash-list=dbd506d6ef76e5f386f41c651dcb808c5bcbd75471cc4eafa3f4df7ad4e4c493 +``` + +### Relay Gossipsub + +The gossip relay can also relay directly from _other_ gossip relays. You can specify multiple peers to directly connect with. In this case, a group configuration file must be specified since there's no way to retrieve chain information over pubsub. + +```sh +drand-relay-gossip-relay run -relay=/ip4/127.0.0.1/tcp/44544/p2p/QmPeerID0 \ + -relay=/ip4/127.0.0.1/tcp/44545/p2p/QmPeerID1 \ + -group-conf-list=/home/user/.drand/groups/drand_group.toml +``` + +Alternatively, you can provide URL(s) of HTTP API(s) that can be contacted to retrieve chain information. In this case we must provide the chain `-hash` to verify the information we retrieve is for the chain we expect (or provide the `-insecure` flag): + +```sh +drand-relay-gossip-relay run -relay=/ip4/127.0.0.1/tcp/44544/p2p/QmPeerID0 \ + -relay=/ip4/127.0.0.1/tcp/44545/p2p/QmPeerID1 \ + -url=http://127.0.0.1:3002 \ + -hash-list=6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83 +``` + +If you want to verify multiple networks, you can provide the `-hash-list` flag, e.g.: + +```shell +drand-relay-gossip-relay run -relay=/ip4/127.0.0.1/tcp/44544/p2p/QmPeerID0 \ + -relay=/ip4/127.0.0.1/tcp/44545/p2p/QmPeerID1 \ + -url=http://127.0.0.1:3002 \ + -hash-list=dbd506d6ef76e5f386f41c651dcb808c5bcbd75471cc4eafa3f4df7ad4e4c493,8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce +``` + +### Other options + +#### Bootstrap peers + +If there is a set of peers the gossip relay should connect with and stay connected to then the `-peer-with` flag can be used to specify one or more peer multiaddrs for this purpose. + +#### Failover + +The `-url` flag provides the URL(s) of alternative HTTP API endpoints that may be able to provide randomness in the event of a failure of the gRPC connection/libp2p pubsub network. Each randomness round is raced with the HTTP endpoints when it becomes available such that if gRPC or pubsub take too long to deliver the round it'll be provided over HTTP e.g. + +```sh +drand-relay-gossip-relay run -grpc-connect=127.0.0.1:3000 \ + -insecure \ + -url=http://127.0.0.1:3102 +``` + +```sh +drand-relay-gossip-relay run -relay=/ip4/127.0.0.1/tcp/44544/p2p/QmPeerID0 \ + -relay=/ip4/127.0.0.1/tcp/44545/p2p/QmPeerID1 \ + -hash-list=6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83 \ + -url=http://127.0.0.1:3102 +``` + +#### Configuring the libp2p pubsub node + +Starting a relay will spawn a libp2p pubsub node listening on `/ip4/0.0.0.0/tcp/44544` by default. Use the `-listen` flag to change. To effectively relay drand randomness, your node must be publicly accessible on the network. + +If not specified a libp2p identity will be generated and stored in an `identity.key` file in the current working directory. Use the `-identity` flag to override the location. + +### Usage from a golang drand client + +#### With Group TOML or Chain Info + +```go +package main + +import ( + "context" + "fmt" + + clock "github.com/jonboulle/clockwork" + + "github.com/drand/drand-cli/client" + p2pClient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/log" +) + +const ( + // listenAddr is the multiaddr the local libp2p node should listen on. + listenAddr = "/ip4/0.0.0.0/tcp/4453" + // relayP2PAddr is the p2p multiaddr of the drand gossipsub relay node to connect to. + relayP2PAddr = "/ip4/192.168.1.124/tcp/44544/p2p/QmPeerID" + // groupTOMLPath is the path to the group configuration information (in TOML format). + groupTOMLPath = "/home/user/.drand/groups/drand_group.toml" +) + +func main() { + ctx := context.Background() + l := log.DefaultLogger() + clk := clock.NewRealClock() + + // Create libp2p pubsub + ps, err := p2pClient.NewPubsub(ctx, listenAddr, relayP2PAddr) + if err != nil { + l.Panicw("while creating new p2pClient.NewPubsub", "err", err) + } + + // Extract chain info from group TOML + info, err := chain.InfoFromGroupTOML(l, groupTOMLPath) + if err != nil { + l.Panicw("while extracting info from groupTOML", "err", err) + } + + c, err := client.New(ctx, l, p2pClient.WithPubsub(l, ps, clk, p2pClient.DefaultBufferSize), client.WithChainInfo(info)) + if err != nil { + l.Panicw("while creating a new client", "err", err) + } + + for res := range c.Watch(ctx) { + fmt.Printf("round=%v randomness=%v\n", res.Round(), res.Randomness()) + } +} +``` + +#### With Known Chain Hash + +You do not need to know the full group info to use the pubsub client if you know the chain hash and an HTTP endpoint then you can request the chain info from the HTTP endpoint, verifying it with the known chain hash: + +```go +package main + +import ( + "context" + "encoding/hex" + "fmt" + + clock "github.com/jonboulle/clockwork" + + "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/http" + gclient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand/common/log" +) + +const ( + // listenAddr is the multiaddr the local libp2p node should listen on. + listenAddr = "/ip4/0.0.0.0/tcp/4453" + // relayP2PAddr is the p2p multiaddr of the drand gossipsub relay node to connect to. + relayP2PAddr = "/ip4/192.168.1.124/tcp/44544/p2p/12D3KooWAe637xuWdRCYkuaZZce13P1F9zJX5gzGUPWZJpsUGUSH" + // chainHash is a hash of the group chain information. + chainHash = "c599c267a0dd386606f7d6132da8327d57e1004760897c9dd4fb8495c29942b2" + // httpRelayURL is the URL of a drand HTTP API endpoint. + httpRelayURL = "http://127.0.0.1:3002" +) + +func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + clk := clock.NewRealClock() + + // Create libp2p pubsub + ps, err := gclient.NewPubsub(ctx, listenAddr, relayP2PAddr) + if err != nil { + panic(err) + } + + // Chain hash is used to verify endpoints + hash, err := hex.DecodeString(chainHash) + if err != nil { + panic(err) + } + + c, err := client.New(ctx, lg, + gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), + client.WithChainHash(hash), + client.From(http.ForURLs(ctx, lg, []string{httpRelayURL}, hash)...), + ) + if err != nil { + panic(err) + } + + for res := range c.Watch(ctx) { + fmt.Printf("round=%v randomness=%v\n", res.Round(), res.Randomness()) + } +} +``` + +#### Insecurely + +If you trust the HTTP(S) endpoint, you don't need chain info or a chain hash. Note: using HTTP**S** provides trust at the transport level, but it does not allow verification that the randomness is being requested from the expected chain: + +```go +package main + +import ( + "context" + "fmt" + + clock "github.com/jonboulle/clockwork" + + "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/http" + gclient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand/common/log" +) + +const ( + // listenAddr is the multiaddr the local libp2p node should listen on. + listenAddr = "/ip4/0.0.0.0/tcp/4453" + // relayP2PAddr is the p2p multiaddr of the drand gossipsub relay node to connect to. + relayP2PAddr = "/ip4/192.168.1.124/tcp/44544/p2p/QmPeerID" + // httpRelayURL is the URL of a drand HTTP API endpoint. + httpRelayURL = "http://127.0.0.1:3002" +) + +func main() { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + clk := clock.NewRealClock() + + ps, err := gclient.NewPubsub(ctx, listenAddr, relayP2PAddr) + if err != nil { + panic(err) + } + + c, err := client.New(ctx, lg, + gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), + client.From(http.ForURLs(ctx, lg, []string{httpRelayURL}, nil)...), + client.Insecurely(), + ) + if err != nil { + panic(err) + } + + for res := range c.Watch(ctx) { + fmt.Printf("round=%v randomness=%v\n", res.Round(), res.Randomness()) + } +} +``` diff --git a/gossip-relay/main.go b/gossip-relay/main.go new file mode 100644 index 0000000..64fce2e --- /dev/null +++ b/gossip-relay/main.go @@ -0,0 +1,238 @@ +package main + +import ( + "encoding/hex" + "fmt" + "os" + "path" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/urfave/cli/v2" + + "github.com/drand/drand-cli/internal/lib" + "github.com/drand/drand-cli/internal/lp2p" + "github.com/drand/drand/common/log" +) + +// Automatically set through -ldflags +// Example: go install -ldflags "-X main.buildDate=`date -u +%d/%m/%Y@%H:%M:%S` -X main.gitCommit=`git rev-parse HEAD`" +var ( + gitCommit = "none" + buildDate = "unknown" +) + +func main() { + app := &cli.App{ + Name: "drand-relay-gossip-relay", + Version: "2.0.0", + Usage: "pubsub relay for drand randomness beacon", + Commands: []*cli.Command{runCmd, clientCmd, idCmd}, + } + + // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. + app.EnableBashCompletion = true + + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("drand gossip-relay relay %s (date %v, commit %v)\n", app.Version, buildDate, gitCommit) + } + + err := app.Run(os.Args) + if err != nil { + fmt.Printf("error: %+v\n", err) + os.Exit(1) + } +} + +var ( + idFlag = &cli.StringFlag{ + Name: "identity", + Usage: "path to a file containing a libp2p identity (base64 encoded)", + Value: "identity.key", + EnvVars: []string{"DRAND_GOSSIP_IDENTITY"}, + } + peerWithFlag = &cli.StringSliceFlag{ + Name: "peer-with", + Usage: "peer multiaddr(s) for the relay to direct connect with", + EnvVars: []string{"DRAND_GOSSIP_PEER_WITH"}, + } + storeFlag = &cli.StringFlag{ + Name: "store", + Usage: "datastore directory", + Value: "./datastore", + EnvVars: []string{"DRAND_RELAY_STORE"}, + } + listenFlag = &cli.StringFlag{ + Name: "listen", + Usage: "listening address for libp2p", + Value: "/ip4/0.0.0.0/tcp/44544", + EnvVars: []string{"DRAND_RELAY_LISTEN"}, + } + metricsFlag = &cli.StringFlag{ + Name: "metrics", + Usage: "local host:port to bind a metrics servlet (optional)", + EnvVars: []string{"DRAND_RELAY_METRICS"}, + } +) + +var runCmd = &cli.Command{ + Name: "run", + Usage: "starts a drand gossip-relay relay process", + Flags: append(lib.ClientFlags, []cli.Flag{ + idFlag, + peerWithFlag, + lib.HashListFlag, + lib.GroupConfListFlag, + storeFlag, + listenFlag, + metricsFlag, + }...), + Action: func(cctx *cli.Context) error { + if cctx.IsSet(lib.HashFlag.Name) { + fmt.Printf("--%s is deprecated. Use --%s or --%s instead\n", lib.HashFlag.Name, lib.HashListFlag.Name, lib.GroupConfListFlag.Name) + } + + switch { + case cctx.IsSet(lib.GroupConfListFlag.Name) && cctx.IsSet(lib.HashListFlag.Name): + return fmt.Errorf("only one of --%s and --%s are allowed", lib.GroupConfListFlag.Name, lib.HashListFlag.Name) + case cctx.IsSet(lib.GroupConfListFlag.Name): + groupConfs := cctx.StringSlice(lib.GroupConfListFlag.Name) + for _, groupConf := range groupConfs { + err := boostrapGossipRelayNode(cctx, groupConf, "") + if err != nil { + return err + } + } + case cctx.IsSet(lib.HashListFlag.Name): + hashes, err := computeHashes(cctx) + if err != nil { + return err + } + + for _, hash := range hashes { + err := boostrapGossipRelayNode(cctx, "", hash) + if err != nil { + return err + } + } + case cctx.IsSet(lib.HashFlag.Name): + hash := cctx.String(lib.HashFlag.Name) + if _, err := hex.DecodeString(hash); err != nil { + return fmt.Errorf("decoding hash %q: %w", hash, err) + } + + err := boostrapGossipRelayNode(cctx, "", hash) + if err != nil { + return err + } + default: + if err := boostrapGossipRelayNode(cctx, "", ""); err != nil { + return err + } + } + + // Wait until we are signaled to shutdown. + <-cctx.Context.Done() + + return cctx.Context.Err() + }, +} + +func boostrapGossipRelayNode(cctx *cli.Context, groupConf, chainHash string) error { + err := cctx.Set(lib.GroupConfFlag.Name, groupConf) + if err != nil { + return err + } + + err = cctx.Set(lib.HashFlag.Name, chainHash) + if err != nil { + return err + } + + c, err := lib.Create(cctx, cctx.IsSet(metricsFlag.Name)) + if err != nil { + return fmt.Errorf("constructing client: %w", err) + } + + chainInfo, err := c.Info(cctx.Context) + if err != nil { + return fmt.Errorf("cannot retrieve chain info: %w", err) + } + + if chainHash == "" { + chainHash = hex.EncodeToString(chainInfo.Hash()) + } + + // Set the path to be desired 'storage path / beaconID'. + // This allows running multiple networks via the same beacon. + dataDir := path.Join(cctx.String(storeFlag.Name), chainInfo.ID) + + cfg := &lp2p.GossipRelayConfig{ + ChainHash: chainHash, + PeerWith: cctx.StringSlice(peerWithFlag.Name), + Addr: cctx.String(listenFlag.Name), + DataDir: dataDir, + IdentityPath: cctx.String(idFlag.Name), + Client: c, + } + + l := log.DefaultLogger().With("beaconID", chainInfo.ID) + + _, err = lp2p.NewGossipRelayNode(l, cfg) + if err != nil { + err = fmt.Errorf("could not initialize a new gossip-relay relay node %w", err) + } + return err +} + +func computeHashes(cctx *cli.Context) ([]string, error) { + hashes := cctx.StringSlice(lib.HashListFlag.Name) + if len(hashes) == 0 { + return nil, nil + } + + for _, hash := range hashes { + if _, err := hex.DecodeString(hash); err != nil { + return nil, fmt.Errorf("decoding hash %q: %w", hash, err) + } + } + + return hashes, nil +} + +var clientCmd = &cli.Command{ + Name: "client", + Flags: lib.ClientFlags, + Action: func(cctx *cli.Context) error { + lg := log.New(nil, log.DefaultLevel, false) + cctx.Context = log.ToContext(cctx.Context, lg) + c, err := lib.Create(cctx, false) + if err != nil { + return fmt.Errorf("constructing client: %w", err) + } + + for rand := range c.Watch(cctx.Context) { + lg.Infow("", "client", "got randomness", "round", rand.GetRound(), "signature", rand.GetSignature()[:16]) + } + + return nil + }, +} + +var idCmd = &cli.Command{ + Name: "peerid", + Usage: "prints the libp2p peer ID or creates one if it does not exist", + Flags: []cli.Flag{idFlag}, + Action: func(cctx *cli.Context) error { + lg := log.New(nil, log.DefaultLevel, false) + priv, err := lp2p.LoadOrCreatePrivKey(cctx.String(idFlag.Name), lg) + if err != nil { + return fmt.Errorf("loading p2p key: %w", err) + } + peerID, err := peer.IDFromPrivateKey(priv) + if err != nil { + return fmt.Errorf("computing peerid: %w", err) + } + fmt.Printf("%s\n", peerID) + return nil + }, +} diff --git a/http-relay/main.go b/http-relay/main.go new file mode 100644 index 0000000..8e0d002 --- /dev/null +++ b/http-relay/main.go @@ -0,0 +1,209 @@ +package main + +import ( + "context" + "encoding/hex" + "fmt" + "net" + "net/http" + "net/http/httptest" + "os" + + "github.com/gorilla/handlers" + "github.com/urfave/cli/v2" + + "github.com/drand/drand-cli/internal/lib" + common2 "github.com/drand/drand/common" + "github.com/drand/drand/common/log" + dhttp "github.com/drand/drand/handler/http" +) + +// Automatically set through -ldflags +// Example: go install -ldflags "-X main.buildDate=`date -u +%d/%m/%Y@%H:%M:%S` -X main.gitCommit=`git rev-parse HEAD`" +var ( + gitCommit = "none" + buildDate = "unknown" +) + +const accessLogPermFolder = 0o666 + +var accessLogFlag = &cli.StringFlag{ + Name: "access-log", + Usage: "file to log http-relay accesses to", + EnvVars: []string{"DRAND_RELAY_ACCESS_LOG"}, +} + +var listenFlag = &cli.StringFlag{ + Name: "bind", + Usage: "local host:port to bind the listener", + EnvVars: []string{"DRAND_RELAY_BIND"}, +} + +var metricsFlag = &cli.StringFlag{ + Name: "metrics", + Usage: "local host:port to bind a metrics servlet (optional)", + 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: "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, +} + +// Relay a GRPC connection to an HTTP server. +// +//nolint:gocyclo,funlen +func Relay(c *cli.Context) error { + //tracesProbability := 0.05 + //if c.IsSet(tracesProbabilityFlag.Name) { + // tracesProbability = c.Float64(tracesProbabilityFlag.Name) + //} + // + //_, tracerShutdown := metrics.InitTracer("drand_relay", c.String(tracesFlag.Name), tracesProbability) + //defer tracerShutdown(c.Context) + + version := "2.0.0" + + //if c.IsSet(metricsFlag.Name) { + // metricsListener := metrics.Start(cliLog, c.String(metricsFlag.Name), pprof.WithProfile(), nil) + // defer metricsListener.Close() + // + // if err := metrics.PrivateMetrics.Register(grpcprometheus.DefaultClientMetrics); err != nil { + // return err + // } + //} + + hashFlagSet := c.IsSet(lib.HashFlag.Name) + if hashFlagSet { + return fmt.Errorf("--%s is deprecated on relay http-relay, please use %s instead", lib.HashFlag.Name, lib.HashListFlag.Name) + } + + handler, err := dhttp.New(context.Background(), fmt.Sprintf("drand/%s (%s)", + version, gitCommit)) + if err != nil { + return fmt.Errorf("failed to create rest handler: %w", err) + } + + hashesMap := make(map[string]bool) + if c.IsSet(lib.HashListFlag.Name) { + hashesList := c.StringSlice(lib.HashListFlag.Name) + for _, hash := range hashesList { + hashesMap[hash] = true + } + } else { + hashesMap[common2.DefaultChainHash] = true + } + + skipHashes := make(map[string]bool) + for hash := range hashesMap { + // todo: don't reuse 'c' + if hash != common2.DefaultChainHash { + if _, err := hex.DecodeString(hash); err != nil { + return fmt.Errorf("failed to decode chain hash value: %w", err) + } + if err := c.Set(lib.HashFlag.Name, hash); err != nil { + return fmt.Errorf("failed to initiate chain hash handler: %w", err) + } + } else { + if err := c.Set(lib.HashFlag.Name, ""); err != nil { + return fmt.Errorf("failed to initiate default chain hash handler: %w", err) + } + } + + subCli, err := lib.Create(c, c.IsSet(metricsFlag.Name)) + if err != nil { + log.DefaultLogger().Warnw("failed to create client", "hash", hash, "error", err) + skipHashes[hash] = true + continue + } + + handler.RegisterNewBeaconHandler(subCli, hash) + } + + if len(skipHashes) == len(hashesMap) { + return fmt.Errorf("failed to create any beacon handlers") + } + + if c.IsSet(accessLogFlag.Name) { + logFile, err := os.OpenFile(c.String(accessLogFlag.Name), os.O_CREATE|os.O_APPEND|os.O_WRONLY, accessLogPermFolder) + if err != nil { + return fmt.Errorf("failed to open access log: %w", err) + } + defer logFile.Close() + handler.SetHTTPHandler(handlers.CombinedLoggingHandler(logFile, handler.GetHTTPHandler())) + } else { + handler.SetHTTPHandler(handlers.CombinedLoggingHandler(os.Stdout, handler.GetHTTPHandler())) + } + + bind := "127.0.0.1:0" + if c.IsSet(listenFlag.Name) { + bind = c.String(listenFlag.Name) + } + listener, err := net.Listen("tcp", bind) + if err != nil { + return err + } + + // jumpstart bootup + for hash := range hashesMap { + if skipHashes[hash] { + continue + } + + req, _ := http.NewRequest(http.MethodGet, "/public/0", http.NoBody) + if hash != common2.DefaultChainHash { + req, _ = http.NewRequest(http.MethodGet, fmt.Sprintf("/%s/public/0", hash), http.NoBody) + } + + rr := httptest.NewRecorder() + handler.GetHTTPHandler().ServeHTTP(rr, req) + if rr.Code != http.StatusOK { + log.DefaultLogger().Warnw("", "binary", "relay", "chain-hash", hash, "startup failed", rr.Code) + } + } + + fmt.Printf("Listening at %s\n", listener.Addr()) + // http-relay.Serve is marked as problematic because it does not + // have tweaked timeouts out of the box. + + //nolint + return http.Serve(listener, handler.GetHTTPHandler()) +} + +func main() { + version := common2.GetAppVersion() + lg := log.New(nil, log.DefaultLevel, false) + + app := &cli.App{ + 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, tracesFlag, tracesProbabilityFlag), + Action: func(ctx *cli.Context) error { + ctx.Context = log.ToContext(ctx.Context, lg) + return Relay(ctx) + }, + } + + // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. + app.EnableBashCompletion = true + + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("drand HTTP relay %v (date %v, commit %v)\n", version, buildDate, gitCommit) + } + + err := app.Run(os.Args) + if err != nil { + lg.Fatalw("", "binary", "relay", "err", err) + } +} diff --git a/internal/cli_test.go b/internal/cli_test.go index 7b6dc97..27fcbc0 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -28,7 +28,7 @@ package drand // "github.com/drand/drand-cli/internal/fs" // "github.com/drand/drand-cli/internal/net" // "github.com/drand/drand-cli/internal/test" -// "github.com/drand/drand-cli/internal/test/testlogger" +// "github.com/drand/drand/common/testlogger" // "github.com/drand/drand/common" // chain2 "github.com/drand/drand/common/chain" // "github.com/drand/drand/common/key" @@ -40,31 +40,6 @@ package drand // "github.com/drand/kyber/util/random" //) // -//func TestMigrate(t *testing.T) { -// tmp := getSBFolderStructure(t) -// -// args := []string{"drand", "util", "migrate", "--folder", tmp} -// app := CLI() -// require.NoError(t, app.Run(args)) -// -// l := testlogger.New(t) -// config := core.NewConfig(l, core.WithConfigFolder(tmp)) -// defaultBeaconPath := path.Join(config.ConfigFolderMB(), common.DefaultBeaconID) -// -// newGroupFilePath := path.Join(defaultBeaconPath, key.GroupFolderName) -// newKeyFilePath := path.Join(defaultBeaconPath, key.FolderName) -// newDBFilePath := path.Join(defaultBeaconPath, core.DefaultDBFolder) -// -// if !fs.FolderExists(defaultBeaconPath, newGroupFilePath) { -// t.Errorf("group folder should have been migrated") -// } -// if !fs.FolderExists(defaultBeaconPath, newKeyFilePath) { -// t.Errorf("key folder should have been migrated") -// } -// if !fs.FolderExists(defaultBeaconPath, newDBFilePath) { -// t.Errorf("db folder should have been migrated") -// } -//} // //func TestResetError(t *testing.T) { // beaconID := test.GetBeaconIDFromEnv() diff --git a/internal/lib/cli.go b/internal/lib/cli.go new file mode 100644 index 0000000..050884d --- /dev/null +++ b/internal/lib/cli.go @@ -0,0 +1,244 @@ +package lib + +import ( + "bytes" + "encoding/hex" + "fmt" + "net" + nhttp "net/http" + "os" + "path" + "strings" + + "github.com/google/uuid" + bds "github.com/ipfs/go-ds-badger2" + clock "github.com/jonboulle/clockwork" + pubsub "github.com/libp2p/go-libp2p-pubsub" + ma "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" + + pubClient "github.com/drand/drand-cli/client" + http2 "github.com/drand/drand-cli/client/http" + gclient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand-cli/internal/lp2p" + commonutils "github.com/drand/drand/common" + chainCommon "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" +) + +var ( + // URLFlag is the CLI flag for root URL(s) for fetching randomness. + URLFlag = &cli.StringSliceFlag{ + Name: "url", + Usage: "root URL(s) for fetching randomness", + Aliases: []string{"http-relay-failover"}, // DEPRECATED + } + // HashFlag is the CLI flag for the hash (in hex) of the targeted chain. + HashFlag = &cli.StringFlag{ + Name: "hash", + Usage: "The hash (in hex) of the chain to follow", + Aliases: []string{"chain-hash"}, + } + // HashListFlag is the CLI flag for the hashes list (in hex) for the relay to follow. + HashListFlag = &cli.StringSliceFlag{ + Name: "hash-list", + Usage: "Specify the list (in hex) of hashes the relay should follow", + } + // GroupConfFlag is the CLI flag for specifying the path to the drand group configuration (TOML encoded) or chain info (JSON encoded). + GroupConfFlag = &cli.PathFlag{ + Name: "group-conf", + Usage: "Path to a drand group configuration (TOML encoded) or chain info (JSON encoded)," + + " can be used instead of `-hash` flag to verify the chain.", + } + // GroupConfListFlag is like GroupConfFlag but for a list values. + GroupConfListFlag = &cli.StringSliceFlag{ + Name: "group-conf-list", + Usage: "Paths to at least one drand group configuration (TOML encoded) or chain info (JSON encoded)," + + fmt.Sprintf(" can be used instead of `-%s` flag to verify the chain.", HashListFlag.Name), + } + // InsecureFlag is the CLI flag to allow autodetection of the chain + // information. + InsecureFlag = &cli.BoolFlag{ + Name: "insecure", + Usage: "Allow autodetection of the chain information", + } + // RelayFlag is the CLI flag for relay peer multiaddr(s) to connect with. + RelayFlag = &cli.StringSliceFlag{ + Name: "relay", + Usage: "relay peer multiaddr(s) to connect with", + } + // PortFlag is the CLI flag for local address for client to bind to, when + // connecting to relays. (specified as a numeric port, or a host:port) + PortFlag = &cli.StringFlag{ + Name: "port", + Usage: "Local (host:)port for constructed libp2p host to listen on", + } + + // JSONFlag is the value of the CLI flag `json` enabling JSON output of the loggers + JSONFlag = &cli.BoolFlag{ + Name: "json", + Usage: "Set the output as json format", + } +) + +// ClientFlags is a list of common flags for client creation +var ClientFlags = []cli.Flag{ + URLFlag, + HashFlag, + GroupConfFlag, + InsecureFlag, + RelayFlag, + PortFlag, + JSONFlag, +} + +// Create builds a client, and can be invoked from a cli action supplied +// with ClientFlags +func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) (client.Client, error) { + ctx := c.Context + clients := make([]client.Client, 0) + + var err error + var hash []byte + + l := log.DefaultLogger() + + gc, info, err := buildHTTPClients(c, l, hash, withInstrumentation) + if err != nil { + return nil, err + } + if len(gc) > 0 { + clients = append(clients, gc...) + } + + if c.IsSet(HashFlag.Name) && c.String(HashFlag.Name) != "" { + hash, err = hex.DecodeString(c.String(HashFlag.Name)) + if err != nil { + return nil, err + } + if info != nil && !bytes.Equal(hash, info.Hash()) { + return nil, fmt.Errorf( + "%w for beacon %s %v != %v", + commonutils.ErrInvalidChainHash, + info.ID, + c.String(HashFlag.Name), + hex.EncodeToString(info.Hash()), + ) + } + opts = append(opts, pubClient.WithChainHash(hash)) + } + + if c.Bool(InsecureFlag.Name) { + opts = append(opts, pubClient.Insecurely()) + } + + gopt, err := buildGossipClient(c, l) + if err != nil { + return nil, err + } + opts = append(opts, gopt...) + + return pubClient.Wrap(ctx, l, clients, opts...) +} + +func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumentation bool) ([]client.Client, *chainCommon.Info, error) { + ctx := c.Context + clients := make([]client.Client, 0) + var err error + var skipped []string + var hc client.Client + var info *chainCommon.Info + for _, url := range c.StringSlice(URLFlag.Name) { + hc, err = http2.New(ctx, l, url, hash, nhttp.DefaultTransport) + if err != nil { + l.Warnw("", "client", "failed to load URL", "url", url, "err", err) + skipped = append(skipped, url) + continue + } + info, err = hc.Info(ctx) + if err != nil { + l.Warnw("", "client", "failed to load Info from URL", "url", url, "err", err) + continue + } + + clients = append(clients, hc) + } + + if info != nil { + for _, url := range skipped { + hc, err = http2.NewWithInfo(l, url, info, nhttp.DefaultTransport) + if err != nil { + l.Warnw("", "client", "failed to load URL", "url", url, "err", err) + continue + } + clients = append(clients, hc) + } + } + + if withInstrumentation { + http2.MeasureHeartbeats(c.Context, clients) + } + + return clients, info, nil +} + +func buildGossipClient(c *cli.Context, l log.Logger) ([]pubClient.Option, error) { + if c.IsSet(RelayFlag.Name) { + addrs := c.StringSlice(RelayFlag.Name) + if len(addrs) > 0 { + relayPeers, err := lp2p.ParseMultiaddrSlice(addrs) + if err != nil { + return nil, err + } + listen := "" + if c.IsSet(PortFlag.Name) { + listen = c.String(PortFlag.Name) + } + ps, err := buildClientHost(l, listen, relayPeers) + if err != nil { + return nil, err + } + return []pubClient.Option{gclient.WithPubsub(l, ps, clock.NewRealClock(), gclient.DefaultBufferSize)}, nil + } + } + return []pubClient.Option{}, nil +} + +func buildClientHost(l log.Logger, clientListenAddr string, relayMultiaddr []ma.Multiaddr) (*pubsub.PubSub, error) { + clientID := uuid.New().String() + ds, err := bds.NewDatastore(path.Join(os.TempDir(), "drand-"+clientID+"-datastore"), nil) + if err != nil { + return nil, err + } + priv, err := lp2p.LoadOrCreatePrivKey(path.Join(os.TempDir(), "drand-"+clientID+"-id"), l) + if err != nil { + return nil, err + } + + listen := "" + if clientListenAddr != "" { + bindHost := "0.0.0.0" + if strings.Contains(clientListenAddr, ":") { + host, port, err := net.SplitHostPort(clientListenAddr) + if err != nil { + return nil, err + } + bindHost = host + clientListenAddr = port + } + listen = fmt.Sprintf("/ip4/%s/tcp/%s", bindHost, clientListenAddr) + } + + _, ps, err := lp2p.ConstructHost( + ds, + priv, + listen, + relayMultiaddr, + l, + ) + if err != nil { + return nil, err + } + return ps, nil +} diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 7459b33..9a42e9c 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -1,57 +1,55 @@ package lib -//import ( -// "bytes" -// "context" -// "encoding/hex" -// "errors" -// "os" -// "path/filepath" -// "runtime" -// "testing" -// "time" -// -// clock "github.com/jonboulle/clockwork" -// "github.com/stretchr/testify/require" -// "github.com/urfave/cli/v2" -// -// "github.com/drand/drand-cli/internal/test/mock" -// "github.com/drand/drand-cli/internal/test/testlogger" -// client2 "github.com/drand/drand/client" -// httpmock "github.com/drand/drand/client/test/http/mock" -// commonutils "github.com/drand/drand/common" -// "github.com/drand/drand/common/log" -// "github.com/drand/drand/crypto" -//) -// -//var ( -// opts []client2.Option -//) -// -//const ( -// fakeGossipRelayAddr = "/ip4/8.8.8.8/tcp/9/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" -// fakeChainHash = "6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83" -//) -// -//func mockAction(c *cli.Context) error { -// _, err := Create(c, false, opts...) -// return err -//} -// -//func run(l log.Logger, args []string) error { -// app := cli.NewApp() -// app.Name = "mock-client" -// app.Flags = ClientFlags -// app.Action = func(c *cli.Context) error { -// c.Context = log.ToContext(c.Context, l) -// return mockAction(c) -// } -// -// return app.Run(args) -//} +import ( + "bytes" + "errors" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + clock "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" + + "github.com/drand/drand-cli/client" + httpmock "github.com/drand/drand-cli/client/test/http/mock" + commonutils "github.com/drand/drand/common" + "github.com/drand/drand/common/log" + "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/crypto" +) + +var ( + opts []client.Option +) + +const ( + fakeGossipRelayAddr = "/ip4/8.8.8.8/tcp/9/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx" + fakeChainHash = "6093f9e4320c285ac4aab50ba821cd5678ec7c5015d3d9d11ef89e2a99741e83" +) + +func mockAction(c *cli.Context) error { + _, err := Create(c, false, opts...) + return err +} + +func run(l log.Logger, args []string) error { + app := cli.NewApp() + app.Name = "mock-client" + app.Flags = ClientFlags + app.Action = func(c *cli.Context) error { + c.Context = log.ToContext(c.Context, l) + return mockAction(c) + } + + return app.Run(args) +} + // //func TestClientLib(t *testing.T) { -// opts = []client2.Option{} +// opts = []client.Option{} // lg := testlogger.New(t) // err := run(lg, []string{"mock-client"}) // if err == nil { @@ -77,13 +75,13 @@ package lib // args = []string{"mock-client", "--url", "https://" + addr} // err = run(lg, args) // if err == nil { -// t.Fatal("http needs insecure or hash", err) +// t.Fatal("http-relay needs insecure or hash", err) // } // // args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} // err = run(lg, args) // if err != nil { -// t.Fatal("http should construct", err) +// t.Fatal("http-relay should construct", err) // } // // args = []string{"mock-client", "--relay", fakeGossipRelayAddr} @@ -104,67 +102,67 @@ package lib // t.Fatal("unable to get relay to work", err) // } //} -// -//func TestClientLibGroupConfTOML(t *testing.T) { -// lg := testlogger.New(t) -// err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) -// if err != nil { -// t.Fatal(err) -// } -//} -// -//func TestClientLibGroupConfJSON(t *testing.T) { -// lg := testlogger.New(t) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// clk := clock.NewFakeClockAt(time.Now()) -// addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) -// defer cancel() -// -// var b bytes.Buffer -// require.NoError(t, info.ToJSON(&b, nil)) -// -// infoPath := filepath.Join(t.TempDir(), "info.json") -// -// err = os.WriteFile(infoPath, b.Bytes(), 0644) -// if err != nil { -// t.Fatal(err) -// } -// -// err = run(lg, []string{"mock-client", "--url", "http://" + addr, "--group-conf", infoPath}) -// if err != nil { -// t.Fatal(err) -// } -//} -// -//func TestClientLibChainHashOverrideError(t *testing.T) { -// lg := testlogger.New(t) -// err := run(lg, []string{ -// "mock-client", -// "--relay", -// fakeGossipRelayAddr, -// "--group-conf", -// groupTOMLPath(), -// "--hash", -// fakeChainHash, -// }) -// if !errors.Is(err, commonutils.ErrInvalidChainHash) { -// t.Fatal("expected error from mismatched chain hashes. Got: ", err) -// } -//} -// -//func TestClientLibListenPort(t *testing.T) { -// lg := testlogger.New(t) -// err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) -// if err != nil { -// t.Fatal(err) -// } -//} -// -//func groupTOMLPath() string { -// _, file, _, ok := runtime.Caller(0) -// if !ok { -// return "" -// } -// return filepath.Join(filepath.Dir(file), "..", "..", "internal", "test", "default.toml") -//} + +func TestClientLibGroupConfTOML(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) + if err != nil { + t.Fatal(err) + } +} + +func TestClientLibGroupConfJSON(t *testing.T) { + lg := testlogger.New(t) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + var b bytes.Buffer + require.NoError(t, info.ToJSON(&b, nil)) + + infoPath := filepath.Join(t.TempDir(), "info.json") + + err = os.WriteFile(infoPath, b.Bytes(), 0644) + if err != nil { + t.Fatal(err) + } + + err = run(lg, []string{"mock-client", "--url", "http://" + addr, "--group-conf", infoPath}) + if err != nil { + t.Fatal(err) + } +} + +func TestClientLibChainHashOverrideError(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{ + "mock-client", + "--relay", + fakeGossipRelayAddr, + "--group-conf", + groupTOMLPath(), + "--hash", + fakeChainHash, + }) + if !errors.Is(err, commonutils.ErrInvalidChainHash) { + t.Fatal("expected error from mismatched chain hashes. Got: ", err) + } +} + +func TestClientLibListenPort(t *testing.T) { + lg := testlogger.New(t) + err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) + if err != nil { + t.Fatal(err) + } +} + +func groupTOMLPath() string { + _, file, _, ok := runtime.Caller(0) + if !ok { + return "" + } + return filepath.Join(filepath.Dir(file), "..", "..", "internal", "test", "default.toml") +} diff --git a/internal/lp2p/addrutil.go b/internal/lp2p/addrutil.go new file mode 100644 index 0000000..2f65f74 --- /dev/null +++ b/internal/lp2p/addrutil.go @@ -0,0 +1,77 @@ +package lp2p + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/transport" + ma "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" +) + +const ( + dnsResolveTimeout = 10 * time.Second +) + +// resolveAddresses resolves addresses in parallel +func resolveAddresses(ctx context.Context, addrs []ma.Multiaddr, resolver transport.Resolver) ([]peer.AddrInfo, error) { + ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout) + defer cancel() + + if resolver == nil { + resolver = madns.DefaultResolver + } + + var maddrs []ma.Multiaddr //nolint:prealloc + var wg sync.WaitGroup + resolveErrC := make(chan error, len(addrs)) + + maddrC := make(chan ma.Multiaddr) + + for _, addr := range addrs { + addr := addr + // check whether address ends in `ipfs/Qm...` + if _, last := ma.SplitLast(addr); last.Protocol().Code == ma.P_IPFS { + maddrs = append(maddrs, addr) + continue + } + wg.Add(1) + go func(maddr ma.Multiaddr) { + defer wg.Done() + raddrs, err := resolver.Resolve(ctx, maddr) + if err != nil { + resolveErrC <- fmt.Errorf("failed to resolve \"%s\": %w)", maddr, err) + return + } + // filter out addresses that still doesn't end in `ipfs/Qm...` + found := 0 + for _, raddr := range raddrs { + if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_P2P { + maddrC <- raddr + found++ + } + } + if found == 0 { + resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr) + } + }(addr) + } + go func() { + wg.Wait() + close(maddrC) + }() + + for maddr := range maddrC { + maddrs = append(maddrs, maddr) + } + + select { + case err := <-resolveErrC: + return nil, err + default: + } + return peer.AddrInfosFromP2pAddrs(maddrs...) +} diff --git a/internal/lp2p/addrutil_test.go b/internal/lp2p/addrutil_test.go new file mode 100644 index 0000000..5d2dc21 --- /dev/null +++ b/internal/lp2p/addrutil_test.go @@ -0,0 +1,109 @@ +package lp2p + +import ( + "context" + "errors" + "net" + "strings" + "testing" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" + "github.com/stretchr/testify/require" +) + +const ( + peer0 = "12D3KooW9rwsuYZdWMZfu4hsog3rcDH9okeB9ayAWGzESLwpca78" + peer1 = "12D3KooW9uKWKaPxUSxJySsu2YB3PxaFaXYu8KSZuvLfQxYPu8jj" + dnsaddr0 = "/dnsaddr/example0.com" + dnsaddr1 = "/dnsaddr/example1.com" + p2pIP4Addr0 = "/ip4/192.168.0.1/tcp/44544/p2p/" + peer0 + p2pIP6Addr0 = "/ip6/2001:db8::a3/tcp/44544/p2p/" + peer0 + p2pIP4Addr1 = "/ip4/10.10.10.10/tcp/44544/p2p/" + peer1 + notP2PAddr1 = "/ip4/10.10.10.10/tcp/80" +) + +func mockResolver(t *testing.T, txtRecords map[string][]string) *madns.Resolver { + mock := &madns.MockResolver{ + IP: map[string][]net.IPAddr{}, + TXT: txtRecords, + } + resolver, err := madns.NewResolver(madns.WithDefaultResolver(mock)) + require.NoError(t, err) + return resolver +} + +func findPeer(t *testing.T, ais []peer.AddrInfo, peerIDStr string) peer.AddrInfo { + t.Helper() + peerID, err := peer.Decode(peerIDStr) + if err != nil { + t.Fatal(err) + } + for _, ai := range ais { + if ai.ID == peerID { + return ai + } + } + t.Fatal("not found", peerID) + return peer.AddrInfo{} +} + +func TestResolveDNS(t *testing.T) { + addrs := []multiaddr.Multiaddr{ + multiaddr.StringCast(dnsaddr0), + multiaddr.StringCast(dnsaddr1), + } + txtRecords := map[string][]string{ + "_dnsaddr.example0.com": {"dnsaddr=" + p2pIP4Addr0, "dnsaddr=" + p2pIP6Addr0}, + "_dnsaddr.example1.com": {"dnsaddr=" + p2pIP4Addr1, "dnsaddr=" + notP2PAddr1}, + } + ais, err := resolveAddresses(context.Background(), addrs, mockResolver(t, txtRecords)) + if err != nil { + t.Fatal(err) + } + if len(ais) != 2 { + t.Fatal("expected 2 peers", len(ais)) + } + peer0Info := findPeer(t, ais, peer0) + if len(peer0Info.Addrs) != 2 { + t.Fatal("expected 2 addrs for peer", peer0, peer0Info.Addrs) + } + peer1Info := findPeer(t, ais, peer1) + if len(peer1Info.Addrs) != 1 { + t.Fatal("expected 1 addr for peer", peer1, peer1Info.Addrs) + } +} + +func TestResolveDNSNoAddrs(t *testing.T) { + addrs := []multiaddr.Multiaddr{multiaddr.StringCast(dnsaddr0)} + txtRecords := map[string][]string{"_dnsaddr.example0.com": {}} + _, err := resolveAddresses(context.Background(), addrs, mockResolver(t, txtRecords)) + if err == nil { + t.Fatal("expected error, received no error") + } + if !strings.HasPrefix(err.Error(), "found no ipfs peers at") { + t.Fatal("unexpected error", err) + } +} + +type failBackend struct{} + +func (fb *failBackend) LookupIPAddr(context.Context, string) ([]net.IPAddr, error) { + return nil, errors.New("failBackend") +} +func (fb *failBackend) LookupTXT(context.Context, string) ([]string, error) { + return nil, errors.New("failBackend") +} + +func TestResolveDNSFailure(t *testing.T) { + addrs := []multiaddr.Multiaddr{multiaddr.StringCast(dnsaddr0)} + resolver, _ := madns.NewResolver(madns.WithDefaultResolver(&failBackend{})) + _, err := resolveAddresses(context.Background(), addrs, resolver) + if err == nil { + t.Fatal("expected error, received no error") + } + if !strings.Contains(err.Error(), "failBackend") { + t.Fatal("unexpected error", err) + } +} diff --git a/internal/lp2p/ctor.go b/internal/lp2p/ctor.go new file mode 100644 index 0000000..6655b99 --- /dev/null +++ b/internal/lp2p/ctor.go @@ -0,0 +1,171 @@ +package lp2p + +import ( + "context" + "crypto/rand" + "encoding/base64" + "fmt" + mrand "math/rand" + "os" + "path" + "time" + + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + "github.com/libp2p/go-libp2p" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoreds" + "github.com/libp2p/go-libp2p/p2p/net/connmgr" + "github.com/libp2p/go-libp2p/p2p/security/noise" + libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" + ma "github.com/multiformats/go-multiaddr" + "github.com/pkg/errors" + "golang.org/x/crypto/blake2b" + + dlog "github.com/drand/drand/common/log" +) + +const ( + // userAgent sets the libp2p user-agent which is sent along with the identify protocol. + userAgent = "drand-relay/0.0.0" + // directConnectTicks makes pubsub check it's connected to direct peers every N seconds. + directConnectTicks uint64 = 5 + lowWater = 50 + highWater = 200 + gracePeriod = time.Minute + bootstrapTimeout = 5 * time.Second + allDirPerm = 0755 + identityFilePerm = 0600 +) + +// PubSubTopic generates a drand pubsub topic from a chain hash. +func PubSubTopic(h string) string { + return fmt.Sprintf("/drand/pubsub/v0.0.0/%s", h) +} + +// ConstructHost build a libp2p host configured for relaying drand randomness over pubsub. +func ConstructHost(ds datastore.Datastore, priv crypto.PrivKey, listenAddr string, + bootstrap []ma.Multiaddr, log dlog.Logger) (host.Host, *pubsub.PubSub, error) { + ctx := context.Background() + + pstoreDs := namespace.Wrap(ds, datastore.NewKey("/peerstore")) + pstore, err := pstoreds.NewPeerstore(ctx, pstoreDs, pstoreds.DefaultOpts()) + if err != nil { + return nil, nil, fmt.Errorf("creating peerstore: %w", err) + } + peerID, err := peer.IDFromPrivateKey(priv) + if err != nil { + return nil, nil, fmt.Errorf("computing peerid: %w", err) + } + err = pstore.AddPrivKey(peerID, priv) + if err != nil { + return nil, nil, fmt.Errorf("adding priv to keystore: %w", err) + } + + addrInfos, err := resolveAddresses(ctx, bootstrap, nil) + if err != nil { + return nil, nil, fmt.Errorf("parsing addrInfos: %w", err) + } + + cmgr, err := connmgr.NewConnManager(lowWater, highWater, connmgr.WithGracePeriod(gracePeriod)) + if err != nil { + return nil, nil, fmt.Errorf("constructing connmanager: %w", err) + } + + opts := []libp2p.Option{ + libp2p.Identity(priv), + libp2p.ChainOptions( + libp2p.Security(libp2ptls.ID, libp2ptls.New), + libp2p.Security(noise.ID, noise.New)), + libp2p.DisableRelay(), + // libp2p.Peerstore(pstore), depends on https://github.com/libp2p/go-libp2p-peerstore/issues/153 + libp2p.UserAgent(userAgent), + libp2p.ConnectionManager(cmgr), + } + + if listenAddr != "" { + opts = append(opts, libp2p.ListenAddrStrings(listenAddr)) + } else { + opts = append(opts, libp2p.NoListenAddrs) + } + + h, err := libp2p.New(opts...) + if err != nil { + return nil, nil, fmt.Errorf("constructing host: %w", err) + } + + p, err := pubsub.NewGossipSub(ctx, h, + pubsub.WithPeerExchange(true), + pubsub.WithMessageIdFn(func(pmsg *pubsubpb.Message) string { + hash := blake2b.Sum256(pmsg.Data) + return string(hash[:]) + }), + pubsub.WithDirectPeers(addrInfos), + pubsub.WithFloodPublish(true), + pubsub.WithDirectConnectTicks(directConnectTicks), + ) + if err != nil { + return nil, nil, fmt.Errorf("constructing pubsub: %w", err) + } + + go func() { + mrand.Shuffle(len(addrInfos), func(i, j int) { + addrInfos[i], addrInfos[j] = addrInfos[j], addrInfos[i] + }) + for _, ai := range addrInfos { + ctx, cancel := context.WithTimeout(ctx, bootstrapTimeout) + err := h.Connect(ctx, ai) + cancel() + if err != nil { + log.Warnw("", "construct_host", "could not bootstrap", "addr", ai) + } + } + }() + return h, p, nil +} + +// LoadOrCreatePrivKey loads a base64 encoded libp2p private key from a file or creates one if it does not exist. +func LoadOrCreatePrivKey(identityPath string, log dlog.Logger) (crypto.PrivKey, error) { + privB64, err := os.ReadFile(identityPath) + + var priv crypto.PrivKey + switch { + case err == nil: + privBytes, err := base64.RawStdEncoding.DecodeString(string(privB64)) + if err != nil { + return nil, fmt.Errorf("decoding base64 key: %w", err) + } + priv, err = crypto.UnmarshalEd25519PrivateKey(privBytes) + if err != nil { + return nil, fmt.Errorf("unmarshaling ed25519 key: %w", err) + } + log.Infow("", "load_or_create_priv_key", "loaded private key") + + case errors.Is(err, os.ErrNotExist): + priv, _, err = crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return nil, fmt.Errorf("generating private key: %w", err) + } + b, err := priv.Raw() + if err != nil { + return nil, fmt.Errorf("marshaling private key: %w", err) + } + err = os.MkdirAll(path.Dir(identityPath), allDirPerm) + if err != nil { + return nil, fmt.Errorf("creating identity directory and parents: %w", err) + } + err = os.WriteFile(identityPath, []byte(base64.RawStdEncoding.EncodeToString(b)), identityFilePerm) + if err != nil { + return nil, fmt.Errorf("writing identity file: %w", err) + } + + default: + return nil, fmt.Errorf("getting private key: %w", err) + } + + return priv, nil +} diff --git a/internal/lp2p/ctor_test.go b/internal/lp2p/ctor_test.go new file mode 100644 index 0000000..ade369b --- /dev/null +++ b/internal/lp2p/ctor_test.go @@ -0,0 +1,54 @@ +package lp2p + +import ( + "fmt" + "github.com/drand/drand/common/log" + "path" + "testing" +) + +func TestCreateThenLoadPrivKey(t *testing.T) { + dir := t.TempDir() + + // should not exist yet... + identityPath := path.Join(dir, "identify.key") + + lg := log.DefaultLogger() + priv0, err := LoadOrCreatePrivKey(identityPath, lg) + if err != nil { + t.Fatal(err) + } + + // read again, should be the same + priv1, err := LoadOrCreatePrivKey(identityPath, lg) + if err != nil { + t.Fatal(err) + } + + if !priv0.Equals(priv1) { + t.Fatal(fmt.Errorf("private key not persisted and/or not read back properly")) + } +} + +func TestCreatePrivKeyMkdirp(t *testing.T) { + dir := t.TempDir() + + // should not exist yet and has an intermediate dir that does not exist + identityPath := path.Join(dir, "not-exists-dir", "identify.key") + + lg := log.DefaultLogger() + priv0, err := LoadOrCreatePrivKey(identityPath, lg) + if err != nil { + t.Fatal(err) + } + + // read again, should be the same + priv1, err := LoadOrCreatePrivKey(identityPath, lg) + if err != nil { + t.Fatal(err) + } + + if !priv0.Equals(priv1) { + t.Fatal(fmt.Errorf("private key not persisted and/or not read back properly")) + } +} diff --git a/internal/lp2p/relaynode.go b/internal/lp2p/relaynode.go new file mode 100644 index 0000000..6f16d28 --- /dev/null +++ b/internal/lp2p/relaynode.go @@ -0,0 +1,186 @@ +package lp2p + +import ( + "context" + "fmt" + "time" + + bds "github.com/ipfs/go-ds-badger2" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/host" + ma "github.com/multiformats/go-multiaddr" + "google.golang.org/protobuf/proto" + + client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/protobuf/drand" +) + +// GossipRelayConfig configures a gossip-relay relay node. +type GossipRelayConfig struct { + // ChainHash is a hash that uniquely identifies the drand chain. + ChainHash string + PeerWith []string + Addr string + DataDir string + IdentityPath string + CertPath string + Insecure bool + Client client.Client +} + +// GossipRelayNode is a gossip-relay relay runtime. +type GossipRelayNode struct { + l log.Logger + bootstrap []ma.Multiaddr + ds *bds.Datastore + priv crypto.PrivKey + h host.Host + ps *pubsub.PubSub + t *pubsub.Topic + addrs []ma.Multiaddr + done chan struct{} +} + +// NewGossipRelayNode starts a new gossip-relay relay node. +func NewGossipRelayNode(l log.Logger, cfg *GossipRelayConfig) (*GossipRelayNode, error) { + if cfg.Client == nil { + return nil, fmt.Errorf("no client supplying randomness supplied") + } + + bootstrap, err := ParseMultiaddrSlice(cfg.PeerWith) + if err != nil { + return nil, fmt.Errorf("parsing peer-with: %w", err) + } + + ds, err := bds.NewDatastore(cfg.DataDir, nil) + if err != nil { + return nil, fmt.Errorf("opening datastore: %w", err) + } + + priv, err := LoadOrCreatePrivKey(cfg.IdentityPath, l) + if err != nil { + return nil, fmt.Errorf("loading p2p key: %w", err) + } + + h, ps, err := ConstructHost(ds, priv, cfg.Addr, bootstrap, l) + if err != nil { + return nil, fmt.Errorf("constructing host: %w", err) + } + + addrs, err := h.Network().InterfaceListenAddresses() + if err != nil { + return nil, fmt.Errorf("getting InterfaceListenAddresses: %w", err) + } + + for _, a := range addrs { + l.Infow("", "relay_node", "has addr", "addr", fmt.Sprintf("%s/p2p/%s", a, h.ID())) + } + l.Infow("Joining PubSubTopic", "chainhash", cfg.ChainHash) + t, err := ps.Join(PubSubTopic(cfg.ChainHash)) + if err != nil { + return nil, fmt.Errorf("joining topic: %w", err) + } + + g := &GossipRelayNode{ + l: l, + bootstrap: bootstrap, + ds: ds, + priv: priv, + h: h, + ps: ps, + t: t, + addrs: addrs, + done: make(chan struct{}), + } + + go g.background(cfg.Client) + + return g, nil +} + +// Multiaddrs returns the gossipsub multiaddresses of this relay node. +func (g *GossipRelayNode) Multiaddrs() []ma.Multiaddr { + base := g.h.Addrs() + b := make([]ma.Multiaddr, len(base)) + for i, a := range base { + m, err := ma.NewMultiaddr(fmt.Sprintf("%s/p2p/%s", a, g.h.ID())) + if err != nil { + panic(err) + } + b[i] = m + } + return b +} + +// Shutdown stops the relay node. +func (g *GossipRelayNode) Shutdown() { + close(g.done) +} + +// ParseMultiaddrSlice parses a list of addresses into multiaddrs +func ParseMultiaddrSlice(peers []string) ([]ma.Multiaddr, error) { + out := make([]ma.Multiaddr, len(peers)) + for i, peer := range peers { + m, err := ma.NewMultiaddr(peer) + if err != nil { + return nil, fmt.Errorf("parsing multiaddr\"%s\": %w", peer, err) + } + out[i] = m + } + return out, nil +} + +func (g *GossipRelayNode) background(w client2.Watcher) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + for { + results := w.Watch(ctx) + LOOP: + for { + select { + case res, ok := <-results: + if !ok { + g.l.Warnw("", "relay_node", "watch channel closed") + break LOOP + } + + rd, ok := res.(*client2.RandomData) + if !ok { + g.l.Errorw("", "relay_node", "unexpected client result type") + continue + } + + randB, err := proto.Marshal(&drand.PublicRandResponse{ + Round: res.GetRound(), + Signature: res.GetSignature(), + PreviousSignature: rd.GetPreviousSignature(), + Randomness: res.GetRandomness(), + }) + if err != nil { + g.l.Errorw("", "relay_node", "err marshaling", "err", err) + continue + } + + g.l.Debugw("publishing message", + "relay_node", "publish", + "round", res.GetRound(), + "time.Now", time.Now().Unix(), + ) + + err = g.t.Publish(ctx, randB) + if err != nil { + g.l.Errorw("", "relay_node", "err publishing on pubsub", "err", err) + continue + } + + g.l.Infow("", "relay_node", "Published randomness on pubsub", "round", res.GetRound()) + case <-g.done: + return + } + } + time.Sleep(time.Second) + } +} diff --git a/internal/lp2p/relaynode_test.go b/internal/lp2p/relaynode_test.go new file mode 100644 index 0000000..0183b17 --- /dev/null +++ b/internal/lp2p/relaynode_test.go @@ -0,0 +1,120 @@ +package lp2p + +import ( + "context" + "encoding/hex" + "errors" + "github.com/drand/drand/common/key" + "github.com/drand/drand/crypto" + "github.com/stretchr/testify/require" + "path" + "sync" + "testing" + "time" + + "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/test/result/mock" + "github.com/drand/drand/common/chain" + client2 "github.com/drand/drand/common/client" + "github.com/drand/drand/common/testlogger" +) + +type mockClient struct { + chainInfo *chain.Info + watchF func(context.Context) <-chan client2.Result +} + +func (c *mockClient) Get(_ context.Context, _ uint64) (client2.Result, error) { + return nil, errors.New("unsupported") +} + +func (c *mockClient) Watch(ctx context.Context) <-chan client2.Result { + return c.watchF(ctx) +} + +func (c *mockClient) Info(_ context.Context) (*chain.Info, error) { + return c.chainInfo, nil +} + +func (c *mockClient) RoundAt(_ time.Time) uint64 { + return 0 +} + +func (c *mockClient) Close() error { + return nil +} + +// toRandomDataChain converts the mock results into a chain of client.RandomData +// objects. Note that you do not get back the first result. +func toRandomDataChain(results ...mock.Result) []client.RandomData { + var randomness []client.RandomData + prevSig := results[0].GetSignature() + for i := 1; i < len(results); i++ { + randomness = append(randomness, client.RandomData{ + Rnd: results[i].GetRound(), + Random: results[i].GetRandomness(), + Sig: results[i].GetSignature(), + PreviousSignature: prevSig, + }) + prevSig = results[i].GetSignature() + } + return randomness +} + +func TestWatchRetryOnClose(t *testing.T) { + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) + require.NoError(t, err) + + chainInfo := &chain.Info{ + Period: time.Second, + GenesisTime: time.Now().Unix(), + PublicKey: pair.Public.Key, + } + + results := toRandomDataChain( + mock.NewMockResult(0), + mock.NewMockResult(1), + mock.NewMockResult(2), + mock.NewMockResult(3), + ) + wg := sync.WaitGroup{} + wg.Add(len(results)) + + // return a channel that writes one result then closes + watchF := func(context.Context) <-chan client2.Result { + ch := make(chan client2.Result, 1) + if len(results) > 0 { + res := results[0] + results = results[1:] + ch <- &res + wg.Done() + } + close(ch) + return ch + } + + c := &mockClient{chainInfo, watchF} + + td := t.TempDir() + lg := testlogger.New(t) + gr, err := NewGossipRelayNode(lg, &GossipRelayConfig{ + ChainHash: hex.EncodeToString(chainInfo.Hash()), + Addr: "/ip4/0.0.0.0/tcp/0", + DataDir: td, + IdentityPath: path.Join(td, "identity.key"), + Client: c, + }) + if err != nil { + t.Fatal(err) + } + defer gr.Shutdown() + wg.Wait() + + // even though the watch channel closed, it should have been re-opened by + // the client multiple times until no results remain. + if len(results) != 0 { + t.Fatal("random data items waiting to be consumed", len(results)) + } +} diff --git a/internal/net/client.go b/internal/net/client.go new file mode 100644 index 0000000..be7d4bd --- /dev/null +++ b/internal/net/client.go @@ -0,0 +1,16 @@ +package net + +// HTTPClient is an optional extension to the protocol client relaying of HTTP over the GRPC connection. +import ( + "context" + "net/http" +) + +type Peer interface { + Address() string +} + +// it is currently used for relaying metrics between group members. +type HTTPClient interface { + HandleHTTP(ctx context.Context, p Peer) (http.Handler, error) +} diff --git a/s3-relay/README.md b/s3-relay/README.md new file mode 100644 index 0000000..0c42d5b --- /dev/null +++ b/s3-relay/README.md @@ -0,0 +1,50 @@ +# relay-s3 + +A drand relay that writes randomness rounds to an AWS S3 bucket. + +## Usage + +```sh +drand-relay-s3-relay run [arguments...] +``` + +Note: at minimum you'll need to specify a S3 bucket name and either a HTTP, gRPC or libp2p pubsub drand endpoint to relay from. + +**Example** + +```sh +drand-relay-s3-relay run -hash 138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b -url http://pl-us.testnet.drand.sh -bucket drand-testnet -region eu-west-2 +``` + +### Sync bucket with randomness chain + +The `sync` command will ensure the AWS S3 bucket is fully sync'd with the randomness chain. i.e. it ensures all randomness rounds to date (and generated during the sync) are uploaded to the S3 bucket. This may take a while, but if you need to stop you can start it again from a specific round number using the `-begin` flag. + +```sh +drand-relay-s3-relay sync [arguments...] +``` + +## Prerequesites + +### Credentials + +Ensure AWS credentials file is in `~/.aws/credentials` - it should look like: + +``` +[default] +aws_access_key_id=AKIAIOSFODNN7EXAMPLE +aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +``` + +### S3 bucket + +Ensure you have an S3 bucket ready with _public access_ enabled. The credentials in `~/.aws/credentials` should have write access to it. Make sure the following CORS configuration is applied to allow web applications to request randomness: + +```xml + + + * + GET + + +``` diff --git a/s3-relay/main.go b/s3-relay/main.go new file mode 100644 index 0000000..c6720d8 --- /dev/null +++ b/s3-relay/main.go @@ -0,0 +1,204 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "os" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3/s3manager" + json "github.com/nikkolasg/hexjson" + "github.com/urfave/cli/v2" + + client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/internal/lib" + "github.com/drand/drand/common" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" +) + +// Automatically set through -ldflags +// Example: go install -ldflags "-X main.buildDate=$(date -u +%d/%m/%Y@%H:%M:%S) -X main.gitCommit=$(git rev-parse HEAD)" +var ( + gitCommit = "none" + buildDate = "unknown" +) + +var ( + bucketFlag = &cli.StringFlag{ + Name: "bucket", + Usage: "Name of the AWS bucket to upload to", + Required: true, + EnvVars: []string{"DRAND_S3RELAY_BUCKET"}, + } + regionFlag = &cli.StringFlag{ + Name: "region", + Usage: "Name of the AWS region to use (optional)", + EnvVars: []string{"DRAND_S3RELAY_REGION"}, + } +) + +func main() { + version := common.GetAppVersion() + + app := &cli.App{ + Name: "drand-relay-s3-relay", + Version: version.String(), + Usage: "AWS S3 relay for randomness beacon", + Commands: []*cli.Command{runCmd, syncCmd}, + } + + // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. + app.EnableBashCompletion = true + + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("drand AWS S3 relay %s (date %v, commit %v)\n", version, buildDate, gitCommit) + } + + err := app.Run(os.Args) + if err != nil { + fmt.Printf("error: %+v\n", err) + os.Exit(1) + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "start a drand AWS S3 relay process", + Flags: append(lib.ClientFlags, bucketFlag, regionFlag), + + Action: func(cctx *cli.Context) error { + sess, err := session.NewSession(&aws.Config{Region: aws.String(cctx.String(regionFlag.Name))}) + if err != nil { + return fmt.Errorf("creating aws session: %w", err) + } + + if _, err := sess.Config.Credentials.Get(); err != nil { + return fmt.Errorf("checking credentials: %w", err) + } + + lg := log.New(nil, log.DefaultLevel, false) + cctx.Context = log.ToContext(cctx.Context, lg) + c, err := lib.Create(cctx, false) + if err != nil { + return fmt.Errorf("creating client: %w", err) + } + + upr := s3manager.NewUploader(sess) + watch(context.Background(), lg, c, upr, cctx.String(bucketFlag.Name)) + return nil + }, +} + +func watch(ctx context.Context, l log.Logger, c client2.Watcher, upr *s3manager.Uploader, buc string) { + for { + ch := c.Watch(ctx) + INNER: + for { + select { + case res, ok := <-ch: + if !ok { + l.Warnw("", "relay_s3", "watch channel closed") + t := time.NewTimer(time.Second) + select { + case <-t.C: + break INNER + case <-ctx.Done(): + return + } + } + l.Infow("", "relay_s3", "got randomness", "round", res.GetRound()) + go func(res client.Result) { + url, err := uploadRandomness(ctx, upr, buc, res) + if err != nil { + l.Errorw("", "relay_s3", "failed to upload randomness", "err", err) + return + } + l.Infow("", "relay_s3", "uploaded randomness", "round", res.GetRound(), "location", url) + }(res) + case <-ctx.Done(): + return + } + } + } +} + +func uploadRandomness(ctx context.Context, upr *s3manager.Uploader, buc string, res client.Result) (string, error) { + rd, ok := res.(*client2.RandomData) + if !ok { + return "", fmt.Errorf("unexpected underlying result type") + } + data, err := json.Marshal(rd) + if err != nil { + return "", fmt.Errorf("failed to marshal randomness: %w", err) + } + r, err := upr.UploadWithContext(ctx, &s3manager.UploadInput{ + ACL: aws.String("public-read"), + Bucket: aws.String(buc), + Key: aws.String(fmt.Sprintf("public/%v", res.GetRound())), + Body: bytes.NewBuffer(data), + ContentType: aws.String("application/json"), + CacheControl: aws.String("public, max-age=604800, immutable"), + }) + if err != nil { + return "", err + } + return r.Location, nil +} + +var syncCmd = &cli.Command{ + Name: "sync", + Usage: "sync the AWS S3 bucket with the randomness chain", + Flags: append( + lib.ClientFlags, + bucketFlag, + regionFlag, + &cli.Uint64Flag{ + Name: "begin", + Usage: "Begin syncing from this round number to the latest round.", + Value: 1, + }, + ), + + Action: func(cctx *cli.Context) error { + sess, err := session.NewSession(&aws.Config{Region: aws.String(cctx.String(regionFlag.Name))}) + if err != nil { + return fmt.Errorf("creating aws session: %w", err) + } + + if _, err := sess.Config.Credentials.Get(); err != nil { + return fmt.Errorf("checking credentials: %w", err) + } + + lg := log.New(nil, log.DefaultLevel, false) + cctx.Context = log.ToContext(cctx.Context, lg) + c, err := lib.Create(cctx, false) + if err != nil { + return fmt.Errorf("creating client: %w", err) + } + + buc := cctx.String(bucketFlag.Name) + upr := s3manager.NewUploader(sess) + ctx := context.Background() + + for rnd := cctx.Uint64("begin"); rnd <= c.RoundAt(time.Now()); rnd++ { + // TODO: check if bucket already has this round + r, err := c.Get(ctx, rnd) + if err != nil { + lg.Errorw("", "relay_s3_sync", "failed to get randomness", "round", rnd, "err", err) + continue + } + url, err := uploadRandomness(ctx, upr, buc, r) + if err != nil { + lg.Errorw("", "relay_s3_sync", "failed to upload randomness", "err", err) + continue + } + lg.Infow("", "relay_s3_sync", "uploaded randomness", "round", r.GetRound(), "location", url) + } + + return nil + }, +} From 5f7d7c49e0438e830afc7117383026d5db454ed2 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Wed, 6 Sep 2023 13:42:38 +0200 Subject: [PATCH 06/28] deleting unused S3 relay --- go.mod | 4 +- go.sum | 24 ------ s3-relay/README.md | 50 ----------- s3-relay/main.go | 204 --------------------------------------------- 4 files changed, 1 insertion(+), 281 deletions(-) delete mode 100644 s3-relay/README.md delete mode 100644 s3-relay/main.go diff --git a/go.mod b/go.mod index 5452ccf..13c2571 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.20 replace github.com/drand/drand => ../drand require ( - github.com/aws/aws-sdk-go v1.45.3 github.com/drand/drand v1.5.7 github.com/drand/kyber v1.2.0 github.com/google/uuid v1.3.1 @@ -25,7 +24,6 @@ require ( github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.25.7 golang.org/x/crypto v0.13.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 google.golang.org/protobuf v1.31.0 ) @@ -73,7 +71,6 @@ require ( 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/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect @@ -127,6 +124,7 @@ require ( go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect diff --git a/go.sum b/go.sum index e8820df..aa983ed 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.45.3 h1:Q8BksXg2ZUu2dCbA62+UCEtfvqsW8EO4tzt2IVeYAws= -github.com/aws/aws-sdk-go v1.45.3/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -196,10 +194,6 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= @@ -302,8 +296,6 @@ github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7B github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 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-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= -github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= 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= @@ -413,7 +405,6 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsr github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -461,7 +452,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -477,7 +467,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,8 +485,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -513,7 +500,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -534,25 +520,17 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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-20220722155257-8c9f86f7a55f/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -573,7 +551,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -616,7 +593,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/s3-relay/README.md b/s3-relay/README.md deleted file mode 100644 index 0c42d5b..0000000 --- a/s3-relay/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# relay-s3 - -A drand relay that writes randomness rounds to an AWS S3 bucket. - -## Usage - -```sh -drand-relay-s3-relay run [arguments...] -``` - -Note: at minimum you'll need to specify a S3 bucket name and either a HTTP, gRPC or libp2p pubsub drand endpoint to relay from. - -**Example** - -```sh -drand-relay-s3-relay run -hash 138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b -url http://pl-us.testnet.drand.sh -bucket drand-testnet -region eu-west-2 -``` - -### Sync bucket with randomness chain - -The `sync` command will ensure the AWS S3 bucket is fully sync'd with the randomness chain. i.e. it ensures all randomness rounds to date (and generated during the sync) are uploaded to the S3 bucket. This may take a while, but if you need to stop you can start it again from a specific round number using the `-begin` flag. - -```sh -drand-relay-s3-relay sync [arguments...] -``` - -## Prerequesites - -### Credentials - -Ensure AWS credentials file is in `~/.aws/credentials` - it should look like: - -``` -[default] -aws_access_key_id=AKIAIOSFODNN7EXAMPLE -aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY -``` - -### S3 bucket - -Ensure you have an S3 bucket ready with _public access_ enabled. The credentials in `~/.aws/credentials` should have write access to it. Make sure the following CORS configuration is applied to allow web applications to request randomness: - -```xml - - - * - GET - - -``` diff --git a/s3-relay/main.go b/s3-relay/main.go deleted file mode 100644 index c6720d8..0000000 --- a/s3-relay/main.go +++ /dev/null @@ -1,204 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - "os" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3/s3manager" - json "github.com/nikkolasg/hexjson" - "github.com/urfave/cli/v2" - - client2 "github.com/drand/drand-cli/client" - "github.com/drand/drand-cli/internal/lib" - "github.com/drand/drand/common" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" -) - -// Automatically set through -ldflags -// Example: go install -ldflags "-X main.buildDate=$(date -u +%d/%m/%Y@%H:%M:%S) -X main.gitCommit=$(git rev-parse HEAD)" -var ( - gitCommit = "none" - buildDate = "unknown" -) - -var ( - bucketFlag = &cli.StringFlag{ - Name: "bucket", - Usage: "Name of the AWS bucket to upload to", - Required: true, - EnvVars: []string{"DRAND_S3RELAY_BUCKET"}, - } - regionFlag = &cli.StringFlag{ - Name: "region", - Usage: "Name of the AWS region to use (optional)", - EnvVars: []string{"DRAND_S3RELAY_REGION"}, - } -) - -func main() { - version := common.GetAppVersion() - - app := &cli.App{ - Name: "drand-relay-s3-relay", - Version: version.String(), - Usage: "AWS S3 relay for randomness beacon", - Commands: []*cli.Command{runCmd, syncCmd}, - } - - // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. - app.EnableBashCompletion = true - - cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("drand AWS S3 relay %s (date %v, commit %v)\n", version, buildDate, gitCommit) - } - - err := app.Run(os.Args) - if err != nil { - fmt.Printf("error: %+v\n", err) - os.Exit(1) - } -} - -var runCmd = &cli.Command{ - Name: "run", - Usage: "start a drand AWS S3 relay process", - Flags: append(lib.ClientFlags, bucketFlag, regionFlag), - - Action: func(cctx *cli.Context) error { - sess, err := session.NewSession(&aws.Config{Region: aws.String(cctx.String(regionFlag.Name))}) - if err != nil { - return fmt.Errorf("creating aws session: %w", err) - } - - if _, err := sess.Config.Credentials.Get(); err != nil { - return fmt.Errorf("checking credentials: %w", err) - } - - lg := log.New(nil, log.DefaultLevel, false) - cctx.Context = log.ToContext(cctx.Context, lg) - c, err := lib.Create(cctx, false) - if err != nil { - return fmt.Errorf("creating client: %w", err) - } - - upr := s3manager.NewUploader(sess) - watch(context.Background(), lg, c, upr, cctx.String(bucketFlag.Name)) - return nil - }, -} - -func watch(ctx context.Context, l log.Logger, c client2.Watcher, upr *s3manager.Uploader, buc string) { - for { - ch := c.Watch(ctx) - INNER: - for { - select { - case res, ok := <-ch: - if !ok { - l.Warnw("", "relay_s3", "watch channel closed") - t := time.NewTimer(time.Second) - select { - case <-t.C: - break INNER - case <-ctx.Done(): - return - } - } - l.Infow("", "relay_s3", "got randomness", "round", res.GetRound()) - go func(res client.Result) { - url, err := uploadRandomness(ctx, upr, buc, res) - if err != nil { - l.Errorw("", "relay_s3", "failed to upload randomness", "err", err) - return - } - l.Infow("", "relay_s3", "uploaded randomness", "round", res.GetRound(), "location", url) - }(res) - case <-ctx.Done(): - return - } - } - } -} - -func uploadRandomness(ctx context.Context, upr *s3manager.Uploader, buc string, res client.Result) (string, error) { - rd, ok := res.(*client2.RandomData) - if !ok { - return "", fmt.Errorf("unexpected underlying result type") - } - data, err := json.Marshal(rd) - if err != nil { - return "", fmt.Errorf("failed to marshal randomness: %w", err) - } - r, err := upr.UploadWithContext(ctx, &s3manager.UploadInput{ - ACL: aws.String("public-read"), - Bucket: aws.String(buc), - Key: aws.String(fmt.Sprintf("public/%v", res.GetRound())), - Body: bytes.NewBuffer(data), - ContentType: aws.String("application/json"), - CacheControl: aws.String("public, max-age=604800, immutable"), - }) - if err != nil { - return "", err - } - return r.Location, nil -} - -var syncCmd = &cli.Command{ - Name: "sync", - Usage: "sync the AWS S3 bucket with the randomness chain", - Flags: append( - lib.ClientFlags, - bucketFlag, - regionFlag, - &cli.Uint64Flag{ - Name: "begin", - Usage: "Begin syncing from this round number to the latest round.", - Value: 1, - }, - ), - - Action: func(cctx *cli.Context) error { - sess, err := session.NewSession(&aws.Config{Region: aws.String(cctx.String(regionFlag.Name))}) - if err != nil { - return fmt.Errorf("creating aws session: %w", err) - } - - if _, err := sess.Config.Credentials.Get(); err != nil { - return fmt.Errorf("checking credentials: %w", err) - } - - lg := log.New(nil, log.DefaultLevel, false) - cctx.Context = log.ToContext(cctx.Context, lg) - c, err := lib.Create(cctx, false) - if err != nil { - return fmt.Errorf("creating client: %w", err) - } - - buc := cctx.String(bucketFlag.Name) - upr := s3manager.NewUploader(sess) - ctx := context.Background() - - for rnd := cctx.Uint64("begin"); rnd <= c.RoundAt(time.Now()); rnd++ { - // TODO: check if bucket already has this round - r, err := c.Get(ctx, rnd) - if err != nil { - lg.Errorw("", "relay_s3_sync", "failed to get randomness", "round", rnd, "err", err) - continue - } - url, err := uploadRandomness(ctx, upr, buc, r) - if err != nil { - lg.Errorw("", "relay_s3_sync", "failed to upload randomness", "err", err) - continue - } - lg.Infow("", "relay_s3_sync", "uploaded randomness", "round", r.GetRound(), "location", url) - } - - return nil - }, -} From c3de6126d914daa58106a813d5ce98634e11d91a Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Mon, 16 Oct 2023 17:49:47 +0200 Subject: [PATCH 07/28] attempt at a NewMockHTTPPublicServer --- client/client.go | 31 +---------------- client/client_test.go | 12 +++---- client/http/http_test.go | 10 +++--- client/test/http/mock/httpserver.go | 53 +++++++++++++++++++++++++++-- go.mod | 9 ++++- go.sum | 24 ++++++++++++- gossip-relay/README.md | 53 ----------------------------- internal/lib/cli.go | 4 --- internal/lib/cli_test.go | 4 +-- 9 files changed, 95 insertions(+), 105 deletions(-) diff --git a/client/client.go b/client/client.go index a602c5e..2a50b97 100644 --- a/client/client.go +++ b/client/client.go @@ -46,7 +46,7 @@ func trySetLog(c client.Client, l log.Logger) { // makeClient creates a client from a configuration. func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Client, error) { - if !cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { + if cfg.chainHash == nil && cfg.chainInfo == nil { return nil, errors.New("no root of trust specified") } if len(cfg.clients) == 0 && cfg.watcher == nil { @@ -166,8 +166,6 @@ type clientConfig struct { // chain signature verification back to the 1st round, or to a know result to ensure // determinism in the event of a compromised chain. fullVerify bool - // insecure indicates the root of trust does not need to be present. - insecure bool // autoWatch causes the client to start watching immediately in the background so that new randomness // is proactively fetched and added to the cache. autoWatch bool @@ -212,15 +210,6 @@ func From(c ...client.Client) Option { } } -// Insecurely indicates the client should be allowed to provide randomness -// when the root of trust is not fully provided in a validate-able way. -func Insecurely() Option { - return func(cfg *clientConfig) error { - cfg.insecure = true - return nil - } -} - // WithCacheSize specifies how large of a cache of randomness values should be // kept locally. Default 32 func WithCacheSize(size int) Option { @@ -230,16 +219,6 @@ func WithCacheSize(size int) Option { } } -// WithLogger overrides the logging options for the client, -// allowing specification of additional tags, or redirection / configuration -// of logging level and output. -func WithLogger(l log.Logger) Option { - return func(cfg *clientConfig) error { - cfg.log = l - return nil - } -} - // WithChainHash configures the client to root trust with a given randomness // chain hash, the chain parameters will be fetched from an HTTP endpoint. func WithChainHash(chainHash []byte) Option { @@ -326,11 +305,3 @@ func WithAutoWatchRetry(interval time.Duration) Option { return nil } } - -// WithPrometheus specifies a registry into which to report metrics -func WithPrometheus(r prometheus.Registerer) Option { - return func(cfg *clientConfig) error { - cfg.prometheus = r - return nil - } -} diff --git a/client/client_test.go b/client/client_test.go index 02811de..a605171 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -40,7 +40,7 @@ func TestClientConstraints(t *testing.T) { // As we will run is insecurely, we will set chain info so client can fetch it c.OptionalInfo = fakeChainInfo(t) - if _, e := client2.New(ctx, lg, client2.From(c), client2.Insecurely()); e != nil { + if _, e := client2.New(ctx, lg, client2.From(c)); e != nil { t.Fatal(e) } } @@ -51,10 +51,10 @@ func TestClientMultiple(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - addr2, _, cancel2, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr2, _, cancel2 := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel2() httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1, "http://" + addr2}, chainInfo.Hash()) @@ -110,7 +110,7 @@ func TestClientCache(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() lg := testlogger.New(t) @@ -150,7 +150,7 @@ func TestClientWithoutCache(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() lg := testlogger.New(t) @@ -283,7 +283,7 @@ func TestClientAutoWatch(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() httpClient := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) diff --git a/client/http/http_test.go b/client/http/http_test.go index b2b95bb..f232823 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -22,7 +22,7 @@ func TestHTTPClient(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, true, sch, clk) + addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, true, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -66,7 +66,7 @@ func TestHTTPGetLatest(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -105,7 +105,7 @@ func TestForURLsCreation(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -131,7 +131,7 @@ func TestHTTPWatch(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -166,7 +166,7 @@ func TestHTTPClientClose(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 3e6aa13..e0b8510 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -2,16 +2,63 @@ package mock import ( "context" + "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/key" + "github.com/drand/drand/common/log" + "github.com/drand/drand/common/testlogger" + dhttp "github.com/drand/drand/handler/http" clock "github.com/jonboulle/clockwork" + "net" + "net/http" "testing" + "time" chainCommon "github.com/drand/drand/common/chain" "github.com/drand/drand/crypto" ) // NewMockHTTPPublicServer creates a mock drand HTTP server for testing. -func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chainCommon.Info, context.CancelFunc, func(bool)) { +func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chainCommon.Info, context.CancelFunc) { t.Helper() - //ctx := context.Background() - panic("non-implemented") + lg := testlogger.New(t) + ctx := log.ToContext(context.Background(), lg) + ctx, cancel := context.WithCancel(ctx) + + handler, err := dhttp.New(ctx, "") + if err != nil { + t.Fatal(err) + } + + pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) + if err != nil { + t.Fatal(err) + } + + chainInfo := &chain.Info{ + Period: time.Second, + GenesisTime: clk.Now().Unix(), + PublicKey: pair.Public.Key, + Scheme: sch.Name, + } + + n := uint64(0) + if badSecondRound { + n = 149 + } + client := mock.ClientWithResults(n, 150) + handler.RegisterNewBeaconHandler(client, chainInfo.HashString()) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + httpServer := http.Server{Handler: handler.GetHTTPHandler(), ReadHeaderTimeout: 3 * time.Second} + go httpServer.Serve(listener) + + return listener.Addr().String(), chainInfo, func() { + httpServer.Shutdown(ctx) + cancel() + } } diff --git a/go.mod b/go.mod index 13c2571..eae8dca 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/BurntSushi/toml v1.3.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // 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 @@ -62,6 +63,7 @@ require ( github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230901174712-0191c66da455 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.6 // indirect github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect @@ -117,11 +119,15 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 // indirect go.opentelemetry.io/otel v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.17.0 // indirect + go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect - go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect @@ -131,6 +137,7 @@ require ( golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.13.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.57.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index aa983ed..d10c24e 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -89,11 +90,14 @@ github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwU github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -105,10 +109,12 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.0.3 h1:WkVBY59mw7qUNTr/bLwO7J2vesJ0rQ2C3tMXrTd3w5M= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -148,6 +154,7 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= 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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -156,6 +163,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy 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/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -309,6 +317,9 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 h1:0R5mDLI66Qw13qN80TRz85zthQ2nf2+uDyiV23w6c3Q= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= @@ -346,6 +357,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR 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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sercand/kuberesolver/v4 v4.0.0 h1:frL7laPDG/lFm5n98ODmWnn+cvPpzlkf3LhzuPhcHP4= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -371,6 +383,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 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/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -393,12 +406,16 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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 h1:G4QSBfvPKvg5ZM2j9MrJFdfI5iSljY/WnJqOGFao6HI= +github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= 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-20230728070032-dd9e68f319d5 h1:nORobjToZAvi54wcuUXLq+XG2Rsr0XEizy5aHBHvqWQ= +github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -414,14 +431,19 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0/go.mod h1: go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= +go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -431,7 +453,6 @@ go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -571,6 +592,7 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= +google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= diff --git a/gossip-relay/README.md b/gossip-relay/README.md index a9468b7..282c320 100644 --- a/gossip-relay/README.md +++ b/gossip-relay/README.md @@ -280,56 +280,3 @@ func main() { } } ``` - -#### Insecurely - -If you trust the HTTP(S) endpoint, you don't need chain info or a chain hash. Note: using HTTP**S** provides trust at the transport level, but it does not allow verification that the randomness is being requested from the expected chain: - -```go -package main - -import ( - "context" - "fmt" - - clock "github.com/jonboulle/clockwork" - - "github.com/drand/drand-cli/client" - "github.com/drand/drand-cli/client/http" - gclient "github.com/drand/drand-cli/client/lp2p" - "github.com/drand/drand/common/log" -) - -const ( - // listenAddr is the multiaddr the local libp2p node should listen on. - listenAddr = "/ip4/0.0.0.0/tcp/4453" - // relayP2PAddr is the p2p multiaddr of the drand gossipsub relay node to connect to. - relayP2PAddr = "/ip4/192.168.1.124/tcp/44544/p2p/QmPeerID" - // httpRelayURL is the URL of a drand HTTP API endpoint. - httpRelayURL = "http://127.0.0.1:3002" -) - -func main() { - ctx := context.Background() - lg := log.New(nil, log.DebugLevel, true) - clk := clock.NewRealClock() - - ps, err := gclient.NewPubsub(ctx, listenAddr, relayP2PAddr) - if err != nil { - panic(err) - } - - c, err := client.New(ctx, lg, - gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), - client.From(http.ForURLs(ctx, lg, []string{httpRelayURL}, nil)...), - client.Insecurely(), - ) - if err != nil { - panic(err) - } - - for res := range c.Watch(ctx) { - fmt.Printf("round=%v randomness=%v\n", res.Round(), res.Randomness()) - } -} -``` diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 050884d..6abac82 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -129,10 +129,6 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) opts = append(opts, pubClient.WithChainHash(hash)) } - if c.Bool(InsecureFlag.Name) { - opts = append(opts, pubClient.Insecurely()) - } - gopt, err := buildGossipClient(c, l) if err != nil { return nil, err diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 9a42e9c..14949b5 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -66,7 +66,7 @@ func run(l log.Logger, args []string) error { // go grpcLis.Start() // defer grpcLis.Stop(context.Background()) // -// args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} +// args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr()} // err = run(lg, args) // if err != nil { // t.Fatal("GRPC should work", err) @@ -116,7 +116,7 @@ func TestClientLibGroupConfJSON(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, info, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() var b bytes.Buffer From cfc7d23ead2619b454dda36cdc3fc29d380cde2c Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 26 Oct 2023 00:28:30 +0200 Subject: [PATCH 08/28] HTTP relay works as a binary locally now... Tests are still funky --- client/grpc/client.go | 142 ++++ client/grpc/client_test.go | 110 +++ client/grpc/doc.go | 39 + client/optimizing_test.go | 2 +- client/test/http/mock/httpserver.go | 189 ++++- client/test/result/mock/result.go | 11 +- go.mod | 34 +- go.sum | 1130 ++++++++++++++++++++++++++- internal/lib/cli.go | 52 ++ internal/lib/cli_test.go | 113 +-- 10 files changed, 1729 insertions(+), 93 deletions(-) create mode 100644 client/grpc/client.go create mode 100644 client/grpc/client_test.go create mode 100644 client/grpc/doc.go diff --git a/client/grpc/client.go b/client/grpc/client.go new file mode 100644 index 0000000..a748ffd --- /dev/null +++ b/client/grpc/client.go @@ -0,0 +1,142 @@ +package grpc + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "time" + + grpcProm "github.com/grpc-ecosystem/go-grpc-prometheus" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + grpcInsec "google.golang.org/grpc/credentials/insecure" + + localClient "github.com/drand/drand-cli/client" + commonutils "github.com/drand/drand/common" + "github.com/drand/drand/common/chain" + "github.com/drand/drand/common/client" + "github.com/drand/drand/common/log" + "github.com/drand/drand/protobuf/common" + "github.com/drand/drand/protobuf/drand" +) + +const grpcDefaultTimeout = 5 * time.Second + +type grpcClient struct { + address string + chainHash []byte + client drand.PublicClient + conn *grpc.ClientConn + l log.Logger +} + +// New creates a drand client backed by a GRPC connection. +func New(address string, insecure bool, chainHash []byte) (client.Client, error) { + var opts []grpc.DialOption + if insecure { + opts = append(opts, grpc.WithTransportCredentials(grpcInsec.NewCredentials())) + } else { + opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}))) + } + opts = append(opts, + grpc.WithUnaryInterceptor(grpcProm.UnaryClientInterceptor), + grpc.WithStreamInterceptor(grpcProm.StreamClientInterceptor), + ) + conn, err := grpc.Dial(address, opts...) + if err != nil { + return nil, err + } + + return &grpcClient{address, chainHash, drand.NewPublicClient(conn), conn, log.DefaultLogger()}, nil +} + +func asRD(r *drand.PublicRandResponse) *localClient.RandomData { + return &localClient.RandomData{ + Rnd: r.Round, + Random: r.Randomness, + Sig: r.Signature, + PreviousSignature: r.PreviousSignature, + } +} + +// String returns the name of this client. +func (g *grpcClient) String() string { + return fmt.Sprintf("GRPC(%q)", g.address) +} + +// Get returns a the randomness at `round` or an error. +func (g *grpcClient) Get(ctx context.Context, round uint64) (client.Result, error) { + curr, err := g.client.PublicRand(ctx, &drand.PublicRandRequest{Round: round, Metadata: g.getMetadata()}) + if err != nil { + return nil, err + } + if curr == nil { + return nil, errors.New("no received randomness - unexpected gPRC response") + } + + return asRD(curr), nil +} + +// Watch returns new randomness as it becomes available. +func (g *grpcClient) Watch(ctx context.Context) <-chan client.Result { + stream, err := g.client.PublicRandStream(ctx, &drand.PublicRandRequest{Round: 0, Metadata: g.getMetadata()}) + ch := make(chan client.Result, 1) + if err != nil { + close(ch) + return ch + } + go g.translate(stream, ch) + return ch +} + +// Info returns information about the chain. +func (g *grpcClient) Info(ctx context.Context) (*chain.Info, error) { + proto, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) + if err != nil { + return nil, err + } + if proto == nil { + return nil, errors.New("no received group - unexpected gPRC response") + } + return chain.InfoFromProto(proto) +} + +func (g *grpcClient) translate(stream drand.Public_PublicRandStreamClient, out chan<- client.Result) { + defer close(out) + for { + next, err := stream.Recv() + if err != nil || stream.Context().Err() != nil { + if stream.Context().Err() == nil { + g.l.Warnw("", "grpc_client", "public rand stream", "err", err) + } + return + } + out <- asRD(next) + } +} + +func (g *grpcClient) getMetadata() *common.Metadata { + return &common.Metadata{ChainHash: g.chainHash} +} + +func (g *grpcClient) RoundAt(t time.Time) uint64 { + ctx, cancel := context.WithTimeout(context.Background(), grpcDefaultTimeout) + defer cancel() + + info, err := g.client.ChainInfo(ctx, &drand.ChainInfoRequest{Metadata: g.getMetadata()}) + if err != nil { + return 0 + } + return commonutils.CurrentRound(t.Unix(), time.Second*time.Duration(info.Period), info.GenesisTime) +} + +// SetLog configures the client log output +func (g *grpcClient) SetLog(l log.Logger) { + g.l = l +} + +// Close tears down the gRPC connection and all underlying connections. +func (g *grpcClient) Close() error { + return g.conn.Close() +} diff --git a/client/grpc/client_test.go b/client/grpc/client_test.go new file mode 100644 index 0000000..2833322 --- /dev/null +++ b/client/grpc/client_test.go @@ -0,0 +1,110 @@ +package grpc + +import ( + "bytes" + "context" + "github.com/drand/drand/common/log" + clock "github.com/jonboulle/clockwork" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/drand/drand/crypto" + "github.com/drand/drand/test/mock" +) + +func TestClient(t *testing.T) { + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + l, server := mock.NewMockGRPCPublicServer(t, log.DefaultLogger(), "localhost:0", false, sch, clock.NewFakeClock()) + addr := l.Addr() + + go l.Start() + defer l.Stop(context.Background()) + + c, err := New(addr, true, []byte("")) + if err != nil { + t.Fatal(err) + } + result, err := c.Get(context.Background(), 1969) + if err != nil { + t.Fatal(err) + } + if result.GetRound() != 1969 { + t.Fatal("unexpected round.") + } + r2, err := c.Get(context.Background(), 1970) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(r2.GetRandomness(), result.GetRandomness()) { + t.Fatal("unexpected equality") + } + + rat := c.RoundAt(time.Now()) + if rat == 0 { + t.Fatal("round at should function") + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + res := c.Watch(ctx) + go func() { + time.Sleep(50 * time.Millisecond) + server.(mock.Service).EmitRand(false) + }() + r3, ok := <-res + if !ok { + t.Fatal("watch should work") + } + if r3.GetRound() != 1971 { + t.Fatal("unexpected round") + } + cancel() + _ = c.Close() +} + +func TestClientClose(t *testing.T) { + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + l, _ := mock.NewMockGRPCPublicServer(t, log.DefaultLogger(), "localhost:0", false, sch, clock.NewFakeClock()) + addr := l.Addr() + + go l.Start() + defer l.Stop(context.Background()) + + c, err := New(addr, true, []byte("")) + if err != nil { + t.Fatal(err) + } + result, err := c.Get(context.Background(), 1969) + if err != nil { + t.Fatal(err) + } + if result.GetRound() != 1969 { + t.Fatal("unexpected round.") + } + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + for range c.Watch(context.Background()) { + } + wg.Done() + }() + + err = c.Close() + if err != nil { + t.Fatal(err) + } + + _, err = c.Get(context.Background(), 0) + if status.Code(err) != codes.Canceled { + t.Fatal("unexpected error from closed client", err) + } + + wg.Wait() // wait for the watch to close +} diff --git a/client/grpc/doc.go b/client/grpc/doc.go new file mode 100644 index 0000000..ac6e2fe --- /dev/null +++ b/client/grpc/doc.go @@ -0,0 +1,39 @@ +/* +Package grpc provides a drand client implementation that uses drand's gRPC API. + +The client connects to a drand gRPC endpoint to fetch randomness. The gRPC +client has some advantages over the HTTP client - it is more compact +on-the-wire and supports streaming and authentication. + +Example: + + package main + + import ( + "encoding/hex" + + "github.com/drand/drand/client" + "github.com/drand/drand/client/grpc" + ) + + const ( + grpcAddr = "example.drand.grpc.server:4444" + certPath = "/path/to/drand-grpc.cert" + ) + + var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") + + func main() { + gc, err := grpc.New(grpcAddr, certPath, false) + + c, err := client.New( + client.From(gc), + client.WithChainHash(chainHash), + ) + } + +A path to a file that holds TLS credentials for the drand server is required +to validate server connections. Alternatively set the final parameter to +`true` to enable _insecure_ connections (not recommended). +*/ +package grpc diff --git a/client/optimizing_test.go b/client/optimizing_test.go index b968289..a956cd7 100644 --- a/client/optimizing_test.go +++ b/client/optimizing_test.go @@ -2,7 +2,6 @@ package client import ( "context" - "github.com/drand/drand/common/testlogger" "sync" "testing" "time" @@ -10,6 +9,7 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" "github.com/drand/drand/common/client" + "github.com/drand/drand/common/testlogger" ) // waitForSpeedTest waits until all clients have had their initial speed test. diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index e0b8510..0f0efd6 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -2,54 +2,57 @@ package mock import ( "context" - "github.com/drand/drand-cli/client/mock" + "github.com/drand/drand/common" "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/key" - "github.com/drand/drand/common/log" - "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/common/client" dhttp "github.com/drand/drand/handler/http" + "github.com/drand/drand/protobuf/drand" + "github.com/drand/drand/test/mock" clock "github.com/jonboulle/clockwork" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" "net" "net/http" "testing" "time" - chainCommon "github.com/drand/drand/common/chain" "github.com/drand/drand/crypto" ) // NewMockHTTPPublicServer creates a mock drand HTTP server for testing. -func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chainCommon.Info, context.CancelFunc) { +func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chain.Info, context.CancelFunc) { t.Helper() - lg := testlogger.New(t) - ctx := log.ToContext(context.Background(), lg) - ctx, cancel := context.WithCancel(ctx) + + server := mock.NewMockServer(t, badSecondRound, sch, clk) + client := Proxy(server) + ctx, cancel := context.WithCancel(context.Background()) handler, err := dhttp.New(ctx, "") if err != nil { t.Fatal(err) } - pair, err := key.NewKeyPair("fakeChainInfo.test:1234", sch) - if err != nil { - t.Fatal(err) + var chainInfo *chain.Info + for i := 0; i < 3; i++ { + protoInfo, err := server.ChainInfo(ctx, &drand.ChainInfoRequest{}) + if err != nil { + time.Sleep(10 * time.Millisecond) + continue + } + chainInfo, err = chain.InfoFromProto(protoInfo) + if err != nil { + time.Sleep(10 * time.Millisecond) + continue + } + break } - - chainInfo := &chain.Info{ - Period: time.Second, - GenesisTime: clk.Now().Unix(), - PublicKey: pair.Public.Key, - Scheme: sch.Name, + if chainInfo == nil { + t.Fatal("could not use server after 3 attempts.") } - n := uint64(0) - if badSecondRound { - n = 149 - } - client := mock.ClientWithResults(n, 150) handler.RegisterNewBeaconHandler(client, chainInfo.HashString()) - listener, err := net.Listen("tcp", "127.0.0.1:0") + listener, err := net.Listen("tcp", ":0") if err != nil { t.Fatal(err) } @@ -58,7 +61,143 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche go httpServer.Serve(listener) return listener.Addr().String(), chainInfo, func() { - httpServer.Shutdown(ctx) + httpServer.Shutdown(context.Background()) cancel() } } + +// drandProxy is used as a proxy between a Public service (e.g. the node as a server) +// and a Public Client (the client consumed by the HTTP API) +type drandProxy struct { + r drand.PublicServer +} + +// Proxy wraps a server interface into a client interface so it can be queried +func Proxy(s drand.PublicServer) client.Client { + return &drandProxy{s} +} + +// String returns the name of this proxy. +func (d *drandProxy) String() string { + return "Proxy" +} + +// Get returns randomness at a requested round +func (d *drandProxy) Get(ctx context.Context, round uint64) (client.Result, error) { + resp, err := d.r.PublicRand(ctx, &drand.PublicRandRequest{Round: round}) + if err != nil { + return nil, err + } + return &common.Beacon{ + Round: resp.Round, + Signature: resp.Signature, + PreviousSig: resp.PreviousSignature, + }, nil +} + +// Watch returns new randomness as it becomes available. +func (d *drandProxy) Watch(ctx context.Context) <-chan client.Result { + proxy := newStreamProxy(ctx) + go func() { + err := d.r.PublicRandStream(&drand.PublicRandRequest{}, proxy) + if err != nil { + proxy.Close() + } + }() + return proxy.outgoing +} + +// Info returns the parameters of the chain this client is connected to. +// The public key, when it started, and how frequently it updates. +func (d *drandProxy) Info(ctx context.Context) (*chain.Info, error) { + info, err := d.r.ChainInfo(ctx, &drand.ChainInfoRequest{}) + if err != nil { + return nil, err + } + return chain.InfoFromProto(info) +} + +// RoundAt will return the most recent round of randomness that will be available +// at time for the current client. +func (d *drandProxy) RoundAt(t time.Time) uint64 { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + info, err := d.Info(ctx) + if err != nil { + return 0 + } + return common.CurrentRound(t.Unix(), info.Period, info.GenesisTime) +} + +func (d *drandProxy) Close() error { + return nil +} + +// streamProxy directly relays messages of the PublicRandResponse stream. +type streamProxy struct { + ctx context.Context + cancel context.CancelFunc + outgoing chan client.Result +} + +func newStreamProxy(ctx context.Context) *streamProxy { + ctx, cancel := context.WithCancel(ctx) + s := streamProxy{ + ctx: ctx, + cancel: cancel, + outgoing: make(chan client.Result, 1), + } + return &s +} + +func (s *streamProxy) Send(next *drand.PublicRandResponse) error { + d := common.Beacon{ + Round: next.Round, + Signature: next.Signature, + PreviousSig: next.PreviousSignature, + } + select { + case s.outgoing <- &d: + return nil + case <-s.ctx.Done(): + close(s.outgoing) + return s.ctx.Err() + default: + return nil + } +} + +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 +} +func (s *streamProxy) SendHeader(metadata.MD) error { + return nil +} +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(_ interface{}) error { + return nil +} +func (s *streamProxy) RecvMsg(_ interface{}) error { + return nil +} + +func (s *streamProxy) Header() (metadata.MD, error) { + return nil, nil +} + +func (s *streamProxy) Trailer() metadata.MD { + return nil +} +func (s *streamProxy) CloseSend() error { + return nil +} diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index 0105e0e..d5e6c71 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -107,14 +107,21 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { tshare := tbls.SigShare(tsig) sig := tshare.Value() + // chained mode + if sch.Name == crypto.DefaultSchemeID { + previous = make([]byte, len(sig)) + copy(previous[:], sig) + } else { + previous = nil + } + out[i] = Result{ Sig: sig, PSig: previous, Rnd: uint64(i + 1), Rand: crypto.RandomnessFromSignature(sig), } - previous = make([]byte, len(sig)) - copy(previous[:], sig) + } info := chain.Info{ PublicKey: public, diff --git a/go.mod b/go.mod index eae8dca..2d2eee6 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/drand/kyber v1.2.0 github.com/google/uuid v1.3.1 github.com/gorilla/handlers v1.5.1 + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 github.com/ipfs/go-datastore v0.6.0 @@ -23,12 +24,14 @@ require ( github.com/prometheus/client_golang v1.16.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.25.7 - golang.org/x/crypto v0.13.0 + golang.org/x/crypto v0.14.0 + google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 ) require ( github.com/BurntSushi/toml v1.3.2 // indirect + github.com/ardanlabs/darwin/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect @@ -50,19 +53,27 @@ require ( 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/fsnotify/fsnotify v1.5.4 // indirect github.com/go-chi/chi v1.5.4 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/googleapis v1.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/gogo/status v1.0.3 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230901174712-0191c66da455 // indirect + github.com/gorilla/mux v1.7.3 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.6 // indirect @@ -73,10 +84,12 @@ require ( 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/jmoiron/sqlx v1.3.5 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect + github.com/lib/pq v1.10.9 // 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 @@ -104,6 +117,9 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/onsi/ginkgo/v2 v2.12.0 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 // indirect + github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect 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.4.0 // indirect @@ -114,9 +130,18 @@ require ( github.com/quic-go/quic-go v0.38.1 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sercand/kuberesolver/v4 v4.0.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/uber/jaeger-client-go v2.28.0+incompatible // indirect + github.com/uber/jaeger-lib v2.2.0+incompatible // indirect + github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5 // indirect + github.com/weaveworks/promrus v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 // indirect go.opentelemetry.io/otel v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect @@ -126,20 +151,21 @@ require ( go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.25.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.13.0 // indirect + google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/grpc v1.57.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index d10c24e..cf035dc 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,395 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT 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= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +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.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +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/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +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/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +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.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +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/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +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/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +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/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +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.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +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/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +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.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +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/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +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/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +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/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +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/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +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.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +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/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +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= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= @@ -11,30 +399,66 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIo github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= +github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfKxvSy1HMhoes= 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +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/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/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= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -43,6 +467,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -81,6 +506,20 @@ 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/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/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -91,18 +530,34 @@ 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/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.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/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-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-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -110,22 +565,49 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.0.3 h1:WkVBY59mw7qUNTr/bLwO7J2vesJ0rQ2C3tMXrTd3w5M= +github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +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= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -133,35 +615,89 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +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-20230901174712-0191c66da455 h1:YhRUmI1ttDC4sxKY2V62BTI8hCXnyZBV9h38eAanInE= github.com/google/pprof v0.0.0-20230901174712-0191c66da455/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= 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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/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= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +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/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 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.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -169,6 +705,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/arc/v2 v2.0.6 h1:4NU7uP5vSoK6TbaMj3NtY478TTAWLso/vL1gpNrInHg= @@ -178,6 +716,9 @@ github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +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= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= @@ -202,11 +743,20 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +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.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/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= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -217,8 +767,12 @@ github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGC github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +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.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +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= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -227,7 +781,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -252,16 +808,23 @@ github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8S github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= 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/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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -278,8 +841,11 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 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/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/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= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -307,6 +873,8 @@ github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqd 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= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nikkolasg/hexjson v0.1.0 h1:Cgi1MSZVQFoJKYeRpBNEcdF3LB+Zo4fYKsDz7h8uJYQ= @@ -318,27 +886,56 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 h1:0R5mDLI66Qw13qN80TRz85zthQ2nf2+uDyiV23w6c3Q= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +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= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= @@ -351,13 +948,16 @@ github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2Ep github.com/quic-go/webtransport-go v0.5.3/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.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sercand/kuberesolver/v4 v4.0.0 h1:frL7laPDG/lFm5n98ODmWnn+cvPpzlkf3LhzuPhcHP4= +github.com/sercand/kuberesolver/v4 v4.0.0/go.mod h1:F4RGyuRmMAjeXHKL+w4P7AwUnPceEAPAhxUgXZjKgvM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -382,32 +982,49 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= 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/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= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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 h1:G4QSBfvPKvg5ZM2j9MrJFdfI5iSljY/WnJqOGFao6HI= +github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= @@ -415,17 +1032,32 @@ github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6S 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-20230728070032-dd9e68f319d5 h1:nORobjToZAvi54wcuUXLq+XG2Rsr0XEizy5aHBHvqWQ= +github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5/go.mod h1:rgbeLfJUtEr+G74cwFPR1k/4N0kDeaeSv/qhUNE4hm8= github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= +github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +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.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 h1:HKORGpiOY0R0nAPtKx/ub8/7XoHhRooP8yNRkuPfelI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0/go.mod h1:e+y1M74SYXo/FcIx3UATwth2+5dDkM8dBi7eXg1tbw8= go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= @@ -442,15 +1074,20 @@ go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiM go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -458,36 +1095,72 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/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-20211108221036-ceb1ce70b4fa/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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +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-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +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= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -495,23 +1168,92 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +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-20210813160813-60bc85c4be6d/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= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +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.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= 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= @@ -519,43 +1261,134 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-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= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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= @@ -563,34 +1396,254 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +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/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/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +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-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= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +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-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-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= +google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= @@ -599,12 +1652,64 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE 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.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.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +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/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -614,7 +1719,13 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -623,8 +1734,15 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd 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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 6abac82..e4f32fa 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -18,6 +18,7 @@ import ( "github.com/urfave/cli/v2" pubClient "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/grpc" http2 "github.com/drand/drand-cli/client/http" gclient "github.com/drand/drand-cli/client/lp2p" "github.com/drand/drand-cli/internal/lp2p" @@ -34,6 +35,13 @@ var ( Usage: "root URL(s) for fetching randomness", Aliases: []string{"http-relay-failover"}, // DEPRECATED } + // GRPCConnectFlag is the CLI flag for host:port to dial a gRPC randomness + // provider. + GRPCConnectFlag = &cli.StringFlag{ + Name: "grpc-connect", + Usage: "host:port to dial a gRPC randomness provider", + Aliases: []string{"connect"}, // DEPRECATED + } // HashFlag is the CLI flag for the hash (in hex) of the targeted chain. HashFlag = &cli.StringFlag{ Name: "hash", @@ -85,6 +93,7 @@ var ( // ClientFlags is a list of common flags for client creation var ClientFlags = []cli.Flag{ URLFlag, + GRPCConnectFlag, HashFlag, GroupConfFlag, InsecureFlag, @@ -129,6 +138,15 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) opts = append(opts, pubClient.WithChainHash(hash)) } + grc, _, err := buildGrpcClient(c, info) + if err != nil { + return nil, err + } + + if len(grc) > 0 { + clients = append(clients, grc...) + } + gopt, err := buildGossipClient(c, l) if err != nil { return nil, err @@ -138,6 +156,40 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) return pubClient.Wrap(ctx, l, clients, opts...) } +func buildGrpcClient(c *cli.Context, info *chainCommon.Info) ([]client.Client, *chainCommon.Info, error) { + if !c.IsSet(GRPCConnectFlag.Name) { + return nil, info, nil + } + + var hash []byte + if c.IsSet(HashFlag.Name) { + var err error + + hash, err = hex.DecodeString(c.String(HashFlag.Name)) + if err != nil { + return nil, nil, err + } + } + + if info != nil && len(hash) == 0 { + hash = info.Hash() + } + + gc, err := grpc.New(c.String(GRPCConnectFlag.Name), c.Bool(InsecureFlag.Name), hash) + if err != nil { + return nil, nil, err + } + + if info == nil { + info, err = gc.Info(c.Context) + if err != nil { + return nil, nil, err + } + } + + return []client.Client{gc}, info, nil +} + func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumentation bool) ([]client.Client, *chainCommon.Info, error) { ctx := c.Context clients := make([]client.Client, 0) diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 14949b5..2e2883f 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -2,7 +2,10 @@ package lib import ( "bytes" + "context" + "encoding/hex" "errors" + "github.com/drand/drand/test/mock" "os" "path/filepath" "runtime" @@ -47,61 +50,60 @@ func run(l log.Logger, args []string) error { return app.Run(args) } -// -//func TestClientLib(t *testing.T) { -// opts = []client.Option{} -// lg := testlogger.New(t) -// err := run(lg, []string{"mock-client"}) -// if err == nil { -// t.Fatal("need to specify a connection method.", err) -// } -// -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// clk := clock.NewFakeClockAt(time.Now()) -// addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) -// defer cancel() -// -// grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) -// go grpcLis.Start() -// defer grpcLis.Stop(context.Background()) -// -// args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr()} -// err = run(lg, args) -// if err != nil { -// t.Fatal("GRPC should work", err) -// } -// -// args = []string{"mock-client", "--url", "https://" + addr} -// err = run(lg, args) -// if err == nil { -// t.Fatal("http-relay needs insecure or hash", err) -// } -// -// args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} -// err = run(lg, args) -// if err != nil { -// t.Fatal("http-relay should construct", err) -// } -// -// args = []string{"mock-client", "--relay", fakeGossipRelayAddr} -// err = run(lg, args) -// if err == nil { -// t.Fatal("relays need URL to get chain info and hash", err) -// } -// -// args = []string{"mock-client", "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} -// err = run(lg, args) -// if err == nil { -// t.Fatal("relays need URL to get chain info and hash", err) -// } -// -// args = []string{"mock-client", "--url", "http://" + addr, "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} -// err = run(lg, args) -// if err != nil { -// t.Fatal("unable to get relay to work", err) -// } -//} +func TestClientLib(t *testing.T) { + opts = []client.Option{} + lg := testlogger.New(t) + err := run(lg, []string{"mock-client"}) + if err == nil { + t.Fatal("need to specify a connection method.", err) + } + + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) + clk := clock.NewFakeClockAt(time.Now()) + addr, info, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer cancel() + + grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) + go grpcLis.Start() + defer grpcLis.Stop(context.Background()) + + args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr()} + err = run(lg, args) + if err != nil { + t.Fatal("GRPC should work", err) + } + + args = []string{"mock-client", "--url", "https://" + addr} + err = run(lg, args) + if err == nil { + t.Fatal("http-relay needs insecure or hash", err) + } + + args = []string{"mock-client", "--url", "http://" + addr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err != nil { + t.Fatal("http-relay should construct", err) + } + + args = []string{"mock-client", "--relay", fakeGossipRelayAddr} + err = run(lg, args) + if err == nil { + t.Fatal("relays need URL to get chain info and hash", err) + } + + args = []string{"mock-client", "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err == nil { + t.Fatal("relays need URL to get chain info and hash", err) + } + + args = []string{"mock-client", "--url", "http://" + addr, "--relay", fakeGossipRelayAddr, "--hash", hex.EncodeToString(info.Hash())} + err = run(lg, args) + if err != nil { + t.Fatal("unable to get relay to work", err) + } +} func TestClientLibGroupConfTOML(t *testing.T) { lg := testlogger.New(t) @@ -147,6 +149,7 @@ func TestClientLibChainHashOverrideError(t *testing.T) { fakeChainHash, }) if !errors.Is(err, commonutils.ErrInvalidChainHash) { + t.Log(fakeChainHash) t.Fatal("expected error from mismatched chain hashes. Got: ", err) } } From 8c609419c2b57666750843dbe3909f82daa417f8 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Fri, 27 Oct 2023 15:02:00 +0200 Subject: [PATCH 09/28] patching some more --- client/client.go | 13 ++++++++++++- internal/lib/cli.go | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/client/client.go b/client/client.go index 2a50b97..4468f2d 100644 --- a/client/client.go +++ b/client/client.go @@ -46,7 +46,7 @@ func trySetLog(c client.Client, l log.Logger) { // makeClient creates a client from a configuration. func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Client, error) { - if cfg.chainHash == nil && cfg.chainInfo == nil { + if cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { return nil, errors.New("no root of trust specified") } if len(cfg.clients) == 0 && cfg.watcher == nil { @@ -166,6 +166,8 @@ type clientConfig struct { // chain signature verification back to the 1st round, or to a know result to ensure // determinism in the event of a compromised chain. fullVerify bool + // insecure indicates the root of trust does not need to be present. + insecure bool // autoWatch causes the client to start watching immediately in the background so that new randomness // is proactively fetched and added to the cache. autoWatch bool @@ -210,6 +212,15 @@ func From(c ...client.Client) Option { } } +// Insecurely indicates the client should be allowed to provide randomness +// when the root of trust is not fully provided in a validate-able way. +func Insecurely() Option { + return func(cfg *clientConfig) error { + cfg.insecure = true + return nil + } +} + // WithCacheSize specifies how large of a cache of randomness values should be // kept locally. Default 32 func WithCacheSize(size int) Option { diff --git a/internal/lib/cli.go b/internal/lib/cli.go index e4f32fa..d168b22 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -108,17 +108,19 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) ctx := c.Context clients := make([]client.Client, 0) + var info *chainCommon.Info var err error var hash []byte l := log.DefaultLogger() - gc, info, err := buildHTTPClients(c, l, hash, withInstrumentation) + grc, info, err := buildGrpcClient(c, info) if err != nil { return nil, err } - if len(gc) > 0 { - clients = append(clients, gc...) + + if len(grc) > 0 { + clients = append(clients, grc...) } if c.IsSet(HashFlag.Name) && c.String(HashFlag.Name) != "" { @@ -138,13 +140,16 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) opts = append(opts, pubClient.WithChainHash(hash)) } - grc, _, err := buildGrpcClient(c, info) + if c.Bool(InsecureFlag.Name) { + opts = append(opts, pubClient.Insecurely()) + } + + gc, info, err := buildHTTPClients(c, l, hash, withInstrumentation) if err != nil { return nil, err } - - if len(grc) > 0 { - clients = append(clients, grc...) + if len(gc) > 0 { + clients = append(clients, gc...) } gopt, err := buildGossipClient(c, l) From 7c880dd76bfe76c7ad870feb317af28ae0f1dffa Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 30 Nov 2023 12:54:10 +0100 Subject: [PATCH 10/28] WIP Signed-off-by: Yolan Romailler --- client/client.go | 4 +- client/client_test.go | 10 ++++- client/http/http.go | 9 ++-- client/test/http/mock/httpserver.go | 11 +++-- client/test/result/mock/result.go | 16 +++++--- go.mod | 23 ++++++----- go.sum | 64 +++++++++++++++++++++++------ 7 files changed, 97 insertions(+), 40 deletions(-) diff --git a/client/client.go b/client/client.go index 4468f2d..a10514c 100644 --- a/client/client.go +++ b/client/client.go @@ -47,9 +47,11 @@ func trySetLog(c client.Client, l log.Logger) { // makeClient creates a client from a configuration. func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Client, error) { if cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { + l.Errorw("no root of trust specified") return nil, errors.New("no root of trust specified") } if len(cfg.clients) == 0 && cfg.watcher == nil { + l.Errorw("no points of contact specified") return nil, errors.New("no points of contact specified") } @@ -84,7 +86,7 @@ func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Cl verifiers := make([]client.Client, 0, len(cfg.clients)) for _, source := range cfg.clients { - sch, err := crypto.GetSchemeByIDWithDefault(cfg.chainInfo.Scheme) + sch, err := crypto.GetSchemeByID(cfg.chainInfo.Scheme) if err != nil { return nil, fmt.Errorf("invalid scheme name in makeClient: %w", err) } diff --git a/client/client_test.go b/client/client_test.go index a605171..89f87ab 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -3,10 +3,11 @@ package client_test import ( "context" "errors" - "github.com/drand/drand/common/key" "testing" "time" + "github.com/drand/drand/common/key" + clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" @@ -51,18 +52,23 @@ func TestClientMultiple(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) + addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - addr2, _, cancel2 := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr2, chaininfo2, cancel2 := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel2() + t.Log("created mockhttppublicserver", "addr", addr1, "chaininfo", chainInfo) + t.Log("created mockhttppublicserver", "addr", addr2, "chaininfo", chaininfo2) httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1, "http://" + addr2}, chainInfo.Hash()) if len(httpClients) == 0 { t.Error("http clients is empty") return } + t.Log("Created", addr1, addr2) + var c client.Client var e error c, e = client2.New(ctx, diff --git a/client/http/http.go b/client/http/http.go index 28ff0db..51ab763 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -5,13 +5,14 @@ import ( "context" "encoding/hex" "fmt" - client2 "github.com/drand/drand-cli/client" nhttp "net/http" "os" "path" "strings" "time" + client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand/common" chain2 "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" @@ -238,7 +239,7 @@ func (h *httpClient) FetchChainInfo(ctx context.Context, chainHash []byte) (*cha chainInfo, err := chain2.InfoFromJSON(infoBody.Body) if err != nil { - resC <- httpInfoResponse{nil, fmt.Errorf("decoding response: %w", err)} + resC <- httpInfoResponse{nil, fmt.Errorf("decoding response [chain2.InfoFromJSON]: %w", err)} return } @@ -300,8 +301,8 @@ func (h *httpClient) Get(ctx context.Context, round uint64) (client.Result, erro req.Header.Set("User-Agent", h.Agent) randResponse, err := h.client.Do(req) - if err != nil { - resC <- httpGetResponse{nil, fmt.Errorf("doing request: %w", err)} + if err != nil || randResponse.StatusCode != nhttp.StatusOK { + resC <- httpGetResponse{nil, fmt.Errorf("doing request %v: %w", req, err)} return } defer randResponse.Body.Close() diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 0f0efd6..beb71fd 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -2,6 +2,12 @@ package mock import ( "context" + "fmt" + "net" + "net/http" + "testing" + "time" + "github.com/drand/drand/common" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" @@ -11,10 +17,6 @@ import ( clock "github.com/jonboulle/clockwork" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" - "net" - "net/http" - "testing" - "time" "github.com/drand/drand/crypto" ) @@ -25,6 +27,7 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche server := mock.NewMockServer(t, badSecondRound, sch, clk) client := Proxy(server) + fmt.Println(server) ctx, cancel := context.WithCancel(context.Background()) handler, err := dhttp.New(ctx, "") diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index d5e6c71..d691131 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -68,9 +68,14 @@ func (r *Result) AssertValid(t *testing.T) { } } -func sha256Hash(in []byte) []byte { +func sha256Hash(prev []byte, round int) []byte { h := sha256.New() - h.Write(in) + if prev != nil { + _, _ = h.Write(prev) + } + if round > 0 { + _ = binary.Write(h, binary.BigEndian, uint64(round)) + } return h.Sum(nil) } @@ -91,12 +96,13 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { out := make([]Result, count) for i := range out { - var msg []byte if sch.Name == crypto.DefaultSchemeID { - msg = sha256Hash(append(previous[:], roundToBytes(i+1)...)) + // we're in chained mode + msg = sha256Hash(previous[:], i+1) } else { - msg = sha256Hash(roundToBytes(i + 1)) + // we are in unchained mode + msg = sha256Hash(nil, i+1) } sshare := share.PriShare{I: 0, V: secret} diff --git a/go.mod b/go.mod index 2d2eee6..8c9d1f7 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( require ( github.com/BurntSushi/toml v1.3.2 // indirect + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/ardanlabs/darwin/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -53,24 +54,24 @@ require ( 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/fsnotify/fsnotify v1.5.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-chi/chi v1.5.4 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/googleapis v1.1.0 // indirect + github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/gogo/status v1.0.3 // indirect + github.com/gogo/status v1.1.1 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230901174712-0191c66da455 // indirect - github.com/gorilla/mux v1.7.3 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect @@ -117,9 +118,9 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/onsi/ginkgo/v2 v2.12.0 // indirect github.com/opencontainers/runtime-spec v1.1.0 // indirect - github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 // indirect - github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 // indirect - github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect + github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect 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.4.0 // indirect @@ -133,10 +134,10 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sercand/kuberesolver/v4 v4.0.0 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sirupsen/logrus v1.9.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/uber/jaeger-client-go v2.28.0+incompatible // indirect - github.com/uber/jaeger-lib v2.2.0+incompatible // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5 // indirect github.com/weaveworks/promrus v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect diff --git a/go.sum b/go.sum index cf035dc..67b60a9 100644 --- a/go.sum +++ b/go.sum @@ -403,8 +403,11 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -457,7 +460,6 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= @@ -475,6 +477,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -526,11 +529,13 @@ github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= @@ -548,8 +553,9 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= 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.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -564,15 +570,19 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.0.3 h1:WkVBY59mw7qUNTr/bLwO7J2vesJ0rQ2C3tMXrTd3w5M= github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= +github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= +github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= @@ -684,8 +694,9 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= 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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -700,6 +711,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4Zs github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= +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= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -757,6 +769,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -781,6 +794,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -877,6 +891,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +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.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= @@ -885,12 +900,15 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 h1:0R5mDLI66Qw13qN80TRz85zthQ2nf2+uDyiV23w6c3Q= github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= -github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= @@ -986,8 +1004,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= 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= @@ -1021,10 +1039,12 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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 h1:G4QSBfvPKvg5ZM2j9MrJFdfI5iSljY/WnJqOGFao6HI= github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= +github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= +github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= 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/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= @@ -1120,7 +1140,10 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +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= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= @@ -1132,6 +1155,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +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= @@ -1181,6 +1205,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1356,8 +1381,10 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1389,11 +1416,13 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/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= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1461,6 +1490,10 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T 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= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -1525,6 +1558,7 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID 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= @@ -1648,6 +1682,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1: google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +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= @@ -1655,6 +1690,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi 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= @@ -1713,6 +1749,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -1742,6 +1779,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= 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= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= From 711c9114b151cb525c72c75b598f2a129702c17a Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 5 Dec 2023 13:29:23 +0100 Subject: [PATCH 11/28] Patching tests for real this time Signed-off-by: Yolan Romailler --- client/client.go | 3 +- client/client_test.go | 6 ++-- client/optimizing.go | 4 +++ client/test/http/mock/httpserver.go | 13 ++++---- client/test/result/mock/result.go | 15 +++++---- client/verify.go | 2 +- internal/lib/cli.go | 48 +++++++++++++++++++++++++++-- internal/lib/cli_test.go | 6 ++-- internal/test/default.toml | 32 +++++++++++++++++++ 9 files changed, 106 insertions(+), 23 deletions(-) create mode 100644 internal/test/default.toml diff --git a/client/client.go b/client/client.go index a10514c..e65ac18 100644 --- a/client/client.go +++ b/client/client.go @@ -46,7 +46,7 @@ func trySetLog(c client.Client, l log.Logger) { // makeClient creates a client from a configuration. func makeClient(ctx context.Context, l log.Logger, cfg *clientConfig) (client.Client, error) { - if cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { + if !cfg.insecure && cfg.chainHash == nil && cfg.chainInfo == nil { l.Errorw("no root of trust specified") return nil, errors.New("no root of trust specified") } @@ -189,6 +189,7 @@ func (c *clientConfig) tryPopulateInfo(ctx context.Context, clients ...client.Cl if c.chainInfo == nil { ctx, cancel := context.WithTimeout(ctx, clientStartupTimeoutDefault) defer cancel() + for _, cli := range clients { c.chainInfo, err = cli.Info(ctx) if err == nil { diff --git a/client/client_test.go b/client/client_test.go index 89f87ab..6dbea34 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -41,7 +41,7 @@ func TestClientConstraints(t *testing.T) { // As we will run is insecurely, we will set chain info so client can fetch it c.OptionalInfo = fakeChainInfo(t) - if _, e := client2.New(ctx, lg, client2.From(c)); e != nil { + if _, e := client2.New(ctx, lg, client2.From(c), client2.Insecurely()); e != nil { t.Fatal(e) } } @@ -61,14 +61,14 @@ func TestClientMultiple(t *testing.T) { t.Log("created mockhttppublicserver", "addr", addr1, "chaininfo", chainInfo) t.Log("created mockhttppublicserver", "addr", addr2, "chaininfo", chaininfo2) + + // TODO: review this, are we really expecting this to work when the two servers aren't serving the same chainhash? httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1, "http://" + addr2}, chainInfo.Hash()) if len(httpClients) == 0 { t.Error("http clients is empty") return } - t.Log("Created", addr1, addr2) - var c client.Client var e error c, e = client2.New(ctx, diff --git a/client/optimizing.go b/client/optimizing.go index 8c06c18..65c587c 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -235,6 +235,10 @@ func (oc *optimizingClient) fastestClients() []client.Client { // Get returns the randomness at `round` or an error. func (oc *optimizingClient) Get(ctx context.Context, round uint64) (res client.Result, err error) { clients := oc.fastestClients() + // no need to race clients when we have only one + if len(clients) == 1 { + return clients[0].Get(ctx, round) + } var stats []*requestStat ch := raceGet(ctx, clients, round, oc.requestTimeout, oc.requestConcurrency) err = errors.New("no valid clients") diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index beb71fd..5e2de42 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -2,12 +2,12 @@ package mock import ( "context" - "fmt" "net" "net/http" "testing" "time" + localClient "github.com/drand/drand-cli/client" "github.com/drand/drand/common" "github.com/drand/drand/common/chain" "github.com/drand/drand/common/client" @@ -27,7 +27,7 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche server := mock.NewMockServer(t, badSecondRound, sch, clk) client := Proxy(server) - fmt.Println(server) + ctx, cancel := context.WithCancel(context.Background()) handler, err := dhttp.New(ctx, "") @@ -91,10 +91,11 @@ func (d *drandProxy) Get(ctx context.Context, round uint64) (client.Result, erro if err != nil { return nil, err } - return &common.Beacon{ - Round: resp.Round, - Signature: resp.Signature, - PreviousSig: resp.PreviousSignature, + return &localClient.RandomData{ + Rnd: resp.Round, + Random: resp.Randomness, + Sig: resp.Signature, + PreviousSignature: resp.PreviousSignature, }, nil } diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index d691131..e5dcdf1 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -113,14 +113,6 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { tshare := tbls.SigShare(tsig) sig := tshare.Value() - // chained mode - if sch.Name == crypto.DefaultSchemeID { - previous = make([]byte, len(sig)) - copy(previous[:], sig) - } else { - previous = nil - } - out[i] = Result{ Sig: sig, PSig: previous, @@ -128,6 +120,13 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { Rand: crypto.RandomnessFromSignature(sig), } + // chained mode + if sch.Name == crypto.DefaultSchemeID { + previous = make([]byte, len(sig)) + copy(previous[:], sig) + } else { + previous = nil + } } info := chain.Info{ PublicKey: public, diff --git a/client/verify.go b/client/verify.go index 017dac8..9d655c0 100644 --- a/client/verify.go +++ b/client/verify.go @@ -174,7 +174,7 @@ func (v *verifyingClient) getTrustedPreviousSignature(ctx context.Context, round func (v *verifyingClient) verify(ctx context.Context, info *chain2.Info, r *RandomData) (err error) { fetchPrevSignature := v.strict // only useful for chained schemes - ps := r.PreviousSignature + ps := r.GetPreviousSignature() if fetchPrevSignature { ps, err = v.getTrustedPreviousSignature(ctx, r.GetRound()) diff --git a/internal/lib/cli.go b/internal/lib/cli.go index d168b22..5128719 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -10,6 +10,8 @@ import ( "path" "strings" + "github.com/BurntSushi/toml" + "github.com/drand/drand/common/key" "github.com/google/uuid" bds "github.com/ipfs/go-ds-badger2" clock "github.com/jonboulle/clockwork" @@ -111,6 +113,20 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) var info *chainCommon.Info var err error var hash []byte + if groupPath := c.Path(GroupConfFlag.Name); groupPath != "" { + info, err = chainInfoFromGroupTOML(groupPath) + if err != nil { + info, err = chainInfoFromChainInfoJSON(groupPath) + if info == nil || err != nil { + return nil, fmt.Errorf("failed to decode group (%s) : %w", groupPath, err) + } + } + opts = append(opts, pubClient.WithChainInfo(info)) + } + + if info != nil { + hash = info.Hash() + } l := log.DefaultLogger() @@ -118,12 +134,11 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) if err != nil { return nil, err } - if len(grc) > 0 { clients = append(clients, grc...) } - if c.IsSet(HashFlag.Name) && c.String(HashFlag.Name) != "" { + if c.String(HashFlag.Name) != "" { hash, err = hex.DecodeString(c.String(HashFlag.Name)) if err != nil { return nil, err @@ -202,6 +217,9 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta var skipped []string var hc client.Client var info *chainCommon.Info + + l.Infow("Building HTTP clients", "hash", len(hash), "urls", c.StringSlice(URLFlag.Name)) + for _, url := range c.StringSlice(URLFlag.Name) { hc, err = http2.New(ctx, l, url, hash, nhttp.DefaultTransport) if err != nil { @@ -227,6 +245,9 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta } clients = append(clients, hc) } + if !bytes.Equal(hash, info.Hash()) { + l.Warnw("mismatch between retrieved chain info hash and provided hash", "chainInfo", info.Hash(), "provided", hash) + } } if withInstrumentation { @@ -295,3 +316,26 @@ func buildClientHost(l log.Logger, clientListenAddr string, relayMultiaddr []ma. } return ps, nil } + +// chainInfoFromGroupTOML reads a drand group TOML file and returns the chain info. +func chainInfoFromGroupTOML(filePath string) (*chainCommon.Info, error) { + gt := &key.GroupTOML{} + _, err := toml.DecodeFile(filePath, gt) + if err != nil { + return nil, err + } + g := &key.Group{} + err = g.FromTOML(gt) + if err != nil { + return nil, err + } + return chainCommon.NewChainInfo(g), nil +} + +func chainInfoFromChainInfoJSON(filePath string) (*chainCommon.Info, error) { + b, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + return chainCommon.InfoFromJSON(bytes.NewBuffer(b)) +} diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 2e2883f..c1ccdee 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -5,13 +5,14 @@ import ( "context" "encoding/hex" "errors" - "github.com/drand/drand/test/mock" "os" "path/filepath" "runtime" "testing" "time" + "github.com/drand/drand/test/mock" + clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" @@ -68,7 +69,7 @@ func TestClientLib(t *testing.T) { go grpcLis.Start() defer grpcLis.Stop(context.Background()) - args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr()} + args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} err = run(lg, args) if err != nil { t.Fatal("GRPC should work", err) @@ -118,6 +119,7 @@ func TestClientLibGroupConfJSON(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) + addr, info, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() diff --git a/internal/test/default.toml b/internal/test/default.toml new file mode 100644 index 0000000..09bd4cc --- /dev/null +++ b/internal/test/default.toml @@ -0,0 +1,32 @@ +Threshold = 2 +Period = "30s" +CatchupPeriod = "2s" +GenesisTime = 1649948280 +TransitionTime = 1662041790 +GenesisSeed = "4c194718915cb446103b4959d132286176033ef9ab31824ced291ceaf9eb9b59" +SchemeID = "pedersen-bls-chained" +ID = "default" + +[[Nodes]] + Address = "pl2-rpc.incentinet.drand.sh:443" + Key = "8467b7a234c93e7e54d4e8295605c0ccf59e56606b44c4b21714b215e4f7a240f125c66cc5e5c0a73dc9ca602070f1e4" + TLS = true + Signature = "ad1a464fb51a938c2997fada84026715c7fa999869b245d6fa7c68d7b4274f67ee6025bd9e7239375cd31643353a69b90b7a81d18781d298939944adab402046c8bb52164b012156e1487a5226c3aa9448025ac65936446763f5169777537e72" + Index = 0 + +[[Nodes]] + Address = "pl1-rpc.incentinet.drand.sh:443" + Key = "8a5d883e0b363958c74b7c476e6a3e3c29b54f37caebfaba0c24b84a7ccf3d238e91f5e5a789f0251181d8996ec79d72" + TLS = true + Signature = "b4d62c493617999ba34bab9153699a57464b3a68164c84fa2ae95e1ebfe0be3c4e1c04b166d16883d4a72251a4b1bcb207a8f15fb10de1f26927569e221db7deb666feb6b893e38470043344b76660ddd5d44c0f7de21cf12185c6b03e0d0e21" + Index = 1 + +[[Nodes]] + Address = "pl3-rpc.incentinet.drand.sh:443" + Key = "a5a93fb91b52d4840a265a119b1d7a089f294e596ee9e3b7286530e9846848805fd4aafd413524e3d9ea994b3cf34bf9" + TLS = true + Signature = "9604b1efbde1171af8281ee807ac27b9c866a22cba14ba31f53ab3247476f733b57a21f7d130fcab290c8826d56a5e8a07a1fa6936443fbd69dc673a1cf54316b5eb73b490411243c6a5ae0dab3ab2634d4a026b046f715bd46b4a9c7c3b11f7" + Index = 2 + +[PublicKey] + Coefficients = ["88a8227b75dba145599d894d33eebde3b36fef900d456ae2cc4388867adb4769c40359f783750a41b4d17e40f578bfdb", "88300382e9af80b7fb7b78fed9425a108d2fc66f264c3cacace9bea7464d9d9a036410cb546ab1949ab014f893847373"] From 85f89825bb7241b4ab45ee3d6e10bc03bd0122cd Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 5 Dec 2023 14:00:07 +0100 Subject: [PATCH 12/28] typo Signed-off-by: Yolan Romailler --- client/mock/mock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mock/mock.go b/client/mock/mock.go index 74ee5c0..ccd8e25 100644 --- a/client/mock/mock.go +++ b/client/mock/mock.go @@ -38,7 +38,7 @@ func (m *Client) String() string { return "Mock" } -// Get returns a the randomness at `round` or an error. +// Get returns the randomness at `round` or an error. func (m *Client) Get(ctx context.Context, round uint64) (client.Result, error) { m.Lock() if len(m.Results) == 0 { From 38596537924d2a3a38182f9eb964f38dcf8e5da2 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 5 Dec 2023 14:31:28 +0100 Subject: [PATCH 13/28] Using the fixmock branch for drand for now --- go.mod | 4 +--- go.sum | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8c9d1f7..35a3bdc 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,8 @@ module github.com/drand/drand-cli go 1.20 -replace github.com/drand/drand => ../drand - require ( - github.com/drand/drand v1.5.7 + github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 github.com/drand/kyber v1.2.0 github.com/google/uuid v1.3.1 github.com/gorilla/handlers v1.5.1 diff --git a/go.sum b/go.sum index 67b60a9..c275365 100644 --- a/go.sum +++ b/go.sum @@ -499,6 +499,9 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/drand/drand v1.5.7/go.mod h1:jrJ0244yOHNL5V04vazk3mFatjAWm3i6dg6URWwgbXk= +github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 h1:IEW/xLeyaufieO8ZpEynnyMMMYNPcqD4zA1q1ZUiOV0= +github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7/go.mod h1:TzheRfrx2IkjJxF2tjiyXmtCWmkifD+GxATU3Tq/81E= github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xtwfo= github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= From 4d03d2c58a1fcbf4a57fdbf985a055a15b453332 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Mon, 8 Jan 2024 15:04:58 +0100 Subject: [PATCH 14/28] porting https://github.com/drand/drand/pull/1293 --- client/verify.go | 3 +++ client/verify_test.go | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client/verify.go b/client/verify.go index 9d655c0..bbe2d85 100644 --- a/client/verify.go +++ b/client/verify.go @@ -59,6 +59,9 @@ func (v *verifyingClient) Get(ctx context.Context, round uint64) (client.Result, if err := v.verify(ctx, info, rd); err != nil { return nil, err } + if round != 0 && rd.GetRound() != round { + return nil, fmt.Errorf("round mismatch (malicious relay): %d != %d", rd.GetRound(), round) + } return rd, nil } diff --git a/client/verify_test.go b/client/verify_test.go index da0701e..26d337c 100644 --- a/client/verify_test.go +++ b/client/verify_test.go @@ -16,13 +16,13 @@ import ( "github.com/drand/drand/crypto" ) -func mockClientWithVerifiableResults(ctx context.Context, t *testing.T, l log.Logger, n int) (client.Client, []mock.Result) { +func mockClientWithVerifiableResults(ctx context.Context, t *testing.T, l log.Logger, n int, strictRounds bool) (client.Client, []mock.Result) { t.Helper() sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) info, results := mock.VerifiableResults(n, sch) - mc := clientMock.Client{Results: results, StrictRounds: true, OptionalInfo: info} + mc := clientMock.Client{Results: results, StrictRounds: strictRounds, OptionalInfo: info} var c client.Client @@ -50,7 +50,7 @@ func TestVerifyWithOldVerifiedResult(t *testing.T) { func VerifyFuncTest(t *testing.T, clients, upTo int) { ctx := context.Background() l := testlogger.New(t) - c, results := mockClientWithVerifiableResults(ctx, t, l, clients) + c, results := mockClientWithVerifiableResults(ctx, t, l, clients, true) res, err := c.Get(context.Background(), results[upTo].GetRound()) require.NoError(t, err) @@ -59,3 +59,15 @@ func VerifyFuncTest(t *testing.T, clients, upTo int) { t.Fatal("expected to get result.", results[upTo].GetRound(), res.GetRound(), fmt.Sprintf("%v", c)) } } + +func TestGetWithRoundMismatch(t *testing.T) { + ctx := context.Background() + l := testlogger.New(t) + c, results := mockClientWithVerifiableResults(ctx, t, l, 5, false) + for i := 1; i < len(results); i++ { + results[i] = results[0] + } + + _, err := c.Get(context.Background(), 3) + require.ErrorContains(t, err, "round mismatch (malicious relay): 1 != 3") +} From 824966919427b5379cf47a6767c054bd31e68f70 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 21 May 2024 13:49:49 +0200 Subject: [PATCH 15/28] quick updates --- go.mod | 2 +- go.sum | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 35a3bdc..8a5015f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/drand/drand-cli go 1.20 require ( + github.com/BurntSushi/toml v1.3.2 github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 github.com/drand/kyber v1.2.0 github.com/google/uuid v1.3.1 @@ -28,7 +29,6 @@ require ( ) require ( - github.com/BurntSushi/toml v1.3.2 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/ardanlabs/darwin/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect diff --git a/go.sum b/go.sum index c275365..d7ba72d 100644 --- a/go.sum +++ b/go.sum @@ -499,7 +499,6 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/drand/drand v1.5.7/go.mod h1:jrJ0244yOHNL5V04vazk3mFatjAWm3i6dg6URWwgbXk= github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 h1:IEW/xLeyaufieO8ZpEynnyMMMYNPcqD4zA1q1ZUiOV0= github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7/go.mod h1:TzheRfrx2IkjJxF2tjiyXmtCWmkifD+GxATU3Tq/81E= github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= From 7c4dd7c36775dccca0ad6cb9bbd1b3a52ab5e4c3 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 21 May 2024 14:54:24 +0200 Subject: [PATCH 16/28] Applying code review comments --- client/aggregator.go | 3 +- client/cache.go | 3 ++ client/http/http.go | 2 +- client/http/http_test.go | 87 ---------------------------------------- client/optimizing.go | 2 +- client/verify.go | 3 +- 6 files changed, 8 insertions(+), 92 deletions(-) diff --git a/client/aggregator.go b/client/aggregator.go index 61714c8..a1cb9ae 100644 --- a/client/aggregator.go +++ b/client/aggregator.go @@ -151,8 +151,7 @@ func (c *watchAggregator) Watch(ctx context.Context) <-chan client.Result { c.cancelPassive() c.cancelPassive = nil } - // TODO: any reason we are not passing the existing context here? - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(ctx) go c.distribute(c.Client.Watch(ctx), cancel) } return sub.c diff --git a/client/cache.go b/client/cache.go index 6fcb4e7..aa0ead6 100644 --- a/client/cache.go +++ b/client/cache.go @@ -107,6 +107,9 @@ func (c *cachingClient) Watch(ctx context.Context) <-chan client.Result { out := make(chan client.Result) go func() { for result := range in { + if ctx.Err() != nil { + break + } c.cache.Add(result.GetRound(), result) out <- result } diff --git a/client/http/http.go b/client/http/http.go index 51ab763..2ea6b5e 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -150,7 +150,7 @@ func createClient(url string, transport nhttp.RoundTripper) *nhttp.Client { return &hc } -func IsServerReady(ctx context.Context, addr string) (er error) { +func IsServerReady(ctx context.Context, addr string) error { counter := 0 for { // Ping is wrapping its context with a Timeout on maxTimeoutHTTPRequest anyway. diff --git a/client/http/http_test.go b/client/http/http_test.go index f232823..ab2141a 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -207,90 +207,3 @@ func TestHTTPClientClose(t *testing.T) { wg.Wait() // wait for the watch to close } - -//nolint:funlen -//func TestHTTPRelay(t *testing.T) { -// lg := testlogger.New(t) -// ctx := log.ToContext(context.Background(), lg) -// ctx, cancel := context.WithCancel(ctx) -// defer cancel() -// -// clk := clock.NewFakeClockAt(time.Now()) -// c, _ := withClient(t, clk) -// -// handler, err := dhandler.New(ctx, "") -// if err != nil { -// t.Fatal(err) -// } -// -// info, err := c.Info(ctx) -// if err != nil { -// t.Fatal(err) -// } -// -// handler.RegisterNewBeaconHandler(c, info.HashString()) -// -// listener, err := net.Listen("tcp", "127.0.0.1:0") -// if err != nil { -// t.Fatal(err) -// } -// server := http.Server{Handler: handler.GetHTTPHandler()} -// go func() { _ = server.Serve(listener) }() -// defer func() { _ = server.Shutdown(ctx) }() -// -// err = nhttp.IsServerReady(ctx, listener.Addr().String()) -// if err != nil { -// t.Fatal(err) -// } -// -// getChains := fmt.Sprintf("http://%s/chains", listener.Addr().String()) -// resp := getWithCtx(ctx, getChains, t) -// if resp.StatusCode != http.StatusOK { -// t.Error("expected http status code 200") -// } -// var chains []string -// require.NoError(t, json.NewDecoder(resp.Body).Decode(&chains)) -// require.NoError(t, resp.Body.Close()) -// -// if len(chains) != 1 { -// t.Error("expected chain hash qty not valid") -// } -// if chains[0] != info.HashString() { -// t.Error("expected chain hash not valid") -// } -// -// getChain := fmt.Sprintf("http://%s/%s/info", listener.Addr().String(), info.HashString()) -// resp = getWithCtx(ctx, getChain, t) -// cip := new(drand.ChainInfoPacket) -// require.NoError(t, json.NewDecoder(resp.Body).Decode(cip)) -// require.NotNil(t, cip.Hash) -// require.NotNil(t, cip.PublicKey) -// require.NoError(t, resp.Body.Close()) -// -// // Test exported interfaces. -// u := fmt.Sprintf("http://%s/%s/public/2", listener.Addr().String(), info.HashString()) -// resp = getWithCtx(ctx, u, t) -// body := make(map[string]interface{}) -// require.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) -// require.NoError(t, resp.Body.Close()) -// -// if _, ok := body["signature"]; !ok { -// t.Fatal("expected signature in random response.") -// } -// -// u = fmt.Sprintf("http://%s/%s/public/latest", listener.Addr().String(), info.HashString()) -// resp, err = http.Get(u) -// if err != nil { -// t.Fatal(err) -// } -// body = make(map[string]interface{}) -// -// if err = json.NewDecoder(resp.Body).Decode(&body); err != nil { -// t.Fatal(err) -// } -// require.NoError(t, resp.Body.Close()) -// -// if _, ok := body["round"]; !ok { -// t.Fatal("expected signature in latest response.") -// } -//} diff --git a/client/optimizing.go b/client/optimizing.go index 65c587c..08ac0e4 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -25,7 +25,7 @@ const ( // when `Get` is called for on-demand results, and also how many watch // clients are spun up (in addition to clients marked as passive) to // provide results to `Watch` requests. - defaultRequestConcurrency = 1 + defaultRequestConcurrency = 2 // defaultWatchRetryInterval is the time after which a closed watch channel // is re-open when no context error occurred. defaultWatchRetryInterval = time.Second * 30 diff --git a/client/verify.go b/client/verify.go index bbe2d85..7040896 100644 --- a/client/verify.go +++ b/client/verify.go @@ -81,7 +81,8 @@ func (v *verifyingClient) Watch(ctx context.Context) <-chan client.Result { defer close(outCh) for r := range inCh { if err := v.verify(ctx, info, asRandomData(r)); err != nil { - v.log.Warnw("", "verifying_client", "skipping invalid watch round", "round", r.GetRound(), "err", err) + v.log.Errorw("failed signature verification, something nefarious could be going on!", + "round", r.GetRound(), "signature", r.GetSignature(), "err", err) continue } outCh <- r From a6e21251bcdc904dcaca77e30f60a9a52d7eacd9 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Fri, 24 May 2024 10:18:32 +0200 Subject: [PATCH 17/28] updating to drand/v2 and moving grpc client to internals --- client/aggregator.go | 4 +- client/aggregator_test.go | 8 +- client/cache.go | 4 +- client/cache_test.go | 12 +- client/client.go | 8 +- client/client_test.go | 32 +- client/doc.go | 4 +- client/empty.go | 6 +- client/empty_test.go | 4 +- client/http/doc.go | 6 +- client/http/http.go | 8 +- client/http/http_test.go | 14 +- client/http/metric.go | 14 +- client/lp2p/client.go | 8 +- client/lp2p/client_test.go | 8 +- client/lp2p/doc.go | 21 +- client/lp2p/validator.go | 8 +- client/lp2p/validator_test.go | 29 +- client/mock/mock.go | 6 +- client/optimizing.go | 8 +- client/optimizing_test.go | 24 +- client/poll.go | 8 +- client/test/cache/cache.go | 2 +- client/test/http/mock/httpserver.go | 14 +- client/test/result/mock/result.go | 4 +- client/utils_test.go | 8 +- client/verify.go | 10 +- client/verify_test.go | 11 +- client/watcher.go | 2 +- client/watcher_test.go | 2 +- go.mod | 184 ++- go.sum | 1527 ++++------------------ gossip-relay/README.md | 6 +- gossip-relay/main.go | 2 +- http-relay/main.go | 209 --- internal/cli.go | 29 +- internal/cli_test.go | 39 +- {client => internal}/grpc/client.go | 15 +- {client => internal}/grpc/client_test.go | 6 +- {client => internal}/grpc/doc.go | 4 +- internal/lib/cli.go | 12 +- internal/lib/cli_test.go | 19 +- internal/lp2p/ctor.go | 2 +- internal/lp2p/ctor_test.go | 2 +- internal/lp2p/relaynode.go | 6 +- internal/lp2p/relaynode_test.go | 15 +- 46 files changed, 560 insertions(+), 1814 deletions(-) delete mode 100644 http-relay/main.go rename {client => internal}/grpc/client.go (91%) rename {client => internal}/grpc/client_test.go (95%) rename {client => internal}/grpc/doc.go (92%) diff --git a/client/aggregator.go b/client/aggregator.go index a1cb9ae..f4cbc5c 100644 --- a/client/aggregator.go +++ b/client/aggregator.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) const ( diff --git a/client/aggregator_test.go b/client/aggregator_test.go index f41c458..3878793 100644 --- a/client/aggregator_test.go +++ b/client/aggregator_test.go @@ -7,8 +7,8 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) func TestAggregatorClose(t *testing.T) { @@ -23,7 +23,7 @@ func TestAggregatorClose(t *testing.T) { }, } - ac := newWatchAggregator(testlogger.New(t), c, nil, true, 0) + ac := newWatchAggregator(log.New(nil, log.DebugLevel, true), c, nil, true, 0) err := ac.Close() // should cancel the autoWatch and close the underlying client if err != nil { @@ -52,7 +52,7 @@ func TestAggregatorPassive(t *testing.T) { }, } - ac := newWatchAggregator(testlogger.New(t), c, wc, false, 0) + ac := newWatchAggregator(log.New(nil, log.DebugLevel, true), c, wc, false, 0) wc.WatchCh <- &mock.Result{Rnd: 1234} c.WatchCh <- &mock.Result{Rnd: 5678} diff --git a/client/cache.go b/client/cache.go index aa0ead6..4e04993 100644 --- a/client/cache.go +++ b/client/cache.go @@ -6,8 +6,8 @@ import ( lru "github.com/hashicorp/golang-lru" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) // Cache provides a mechanism to check for rounds in the cache. diff --git a/client/cache_test.go b/client/cache_test.go index 049489c..e9e8c06 100644 --- a/client/cache_test.go +++ b/client/cache_test.go @@ -7,8 +7,8 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) func TestCacheGet(t *testing.T) { @@ -17,7 +17,7 @@ func TestCacheGet(t *testing.T) { if err != nil { t.Fatal(err) } - c, err := NewCachingClient(testlogger.New(t), m, cache) + c, err := NewCachingClient(log.New(nil, log.DebugLevel, true), m, cache) if err != nil { t.Fatal(err) } @@ -58,7 +58,7 @@ func TestCacheGetLatest(t *testing.T) { if err != nil { t.Fatal(err) } - c, err := NewCachingClient(testlogger.New(t), m, cache) + c, err := NewCachingClient(log.New(nil, log.DebugLevel, true), m, cache) if err != nil { t.Fatal(err) } @@ -85,7 +85,7 @@ func TestCacheWatch(t *testing.T) { if err != nil { t.Fatal(err) } - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) cache, _ := NewCachingClient(lg, m, arcCache) c := newWatchAggregator(lg, cache, nil, false, 0) ctx, cancel := context.WithCancel(context.Background()) @@ -122,7 +122,7 @@ func TestCacheClose(t *testing.T) { if err != nil { t.Fatal(err) } - ca, err := NewCachingClient(testlogger.New(t), c, cache) + ca, err := NewCachingClient(log.New(nil, log.DebugLevel, true), c, cache) if err != nil { t.Fatal(err) } diff --git a/client/client.go b/client/client.go index e65ac18..6cc8d4e 100644 --- a/client/client.go +++ b/client/client.go @@ -9,10 +9,10 @@ import ( "github.com/prometheus/client_golang/prometheus" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" ) const clientStartupTimeoutDefault = time.Second * 5 diff --git a/client/client_test.go b/client/client_test.go index 6dbea34..1c05e03 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -6,7 +6,8 @@ import ( "testing" "time" - "github.com/drand/drand/common/key" + "github.com/drand/drand/v2/common/key" + "github.com/drand/drand/v2/common/log" clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" @@ -16,15 +17,14 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" httpmock "github.com/drand/drand-cli/client/test/http/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/testlogger" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/crypto" ) func TestClientConstraints(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) if _, e := client2.New(ctx, lg); e == nil { t.Fatal("client can't be created without root of trust") } @@ -48,7 +48,7 @@ func TestClientConstraints(t *testing.T) { func TestClientMultiple(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) @@ -96,7 +96,7 @@ func TestClientWithChainInfo(t *testing.T) { ctx := context.Background() chainInfo := fakeChainInfo(t) - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) hc, err := http.NewWithInfo(lg, "http://nxdomain.local/", chainInfo, nil) require.NoError(t, err) c, err := client2.New(ctx, lg, client2.WithChainInfo(chainInfo), @@ -119,7 +119,7 @@ func TestClientCache(t *testing.T) { addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) if len(httpClients) == 0 { t.Error("http clients is empty") @@ -159,7 +159,7 @@ func TestClientWithoutCache(t *testing.T) { addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) httpClients := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) if len(httpClients) == 0 { t.Error("http clients is empty") @@ -191,7 +191,7 @@ func TestClientWithoutCache(t *testing.T) { func TestClientWithWatcher(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) info, results := mock.VerifiableResults(2, sch) @@ -228,7 +228,7 @@ func TestClientWithWatcher(t *testing.T) { func TestClientWithWatcherCtorError(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) watcherErr := errors.New("boom") watcherCtor := func(chainInfo *chain.Info, _ client2.Cache) (client2.Watcher, error) { return nil, watcherErr @@ -247,7 +247,7 @@ func TestClientWithWatcherCtorError(t *testing.T) { func TestClientChainHashOverrideError(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) chainInfo := fakeChainInfo(t) _, err := client2.Wrap( ctx, @@ -266,7 +266,7 @@ func TestClientChainHashOverrideError(t *testing.T) { func TestClientChainInfoOverrideError(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) chainInfo := fakeChainInfo(t) _, err := client2.Wrap( ctx, @@ -285,7 +285,7 @@ func TestClientChainInfoOverrideError(t *testing.T) { func TestClientAutoWatch(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) @@ -337,7 +337,7 @@ func TestClientAutoWatch(t *testing.T) { func TestClientAutoWatchRetry(t *testing.T) { ctx := context.Background() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) diff --git a/client/doc.go b/client/doc.go index bf64187..eb4bf9c 100644 --- a/client/doc.go +++ b/client/doc.go @@ -12,8 +12,8 @@ Example: "encoding/hex" "fmt" - "github.com/drand/drand/client" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/client" + "github.com/drand/drand/v2/common/log" ) var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") diff --git a/client/empty.go b/client/empty.go index cd987ac..a920d14 100644 --- a/client/empty.go +++ b/client/empty.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" ) const emptyClientStringerValue = "EmptyClient" diff --git a/client/empty_test.go b/client/empty_test.go index f207c79..fc2929e 100644 --- a/client/empty_test.go +++ b/client/empty_test.go @@ -3,11 +3,11 @@ package client import ( "context" "fmt" - commonutils "github.com/drand/drand/common" + commonutils "github.com/drand/drand/v2/common" "testing" "time" - chain2 "github.com/drand/drand/common/client" + chain2 "github.com/drand/drand/v2/common/client" ) func TestEmptyClient(t *testing.T) { diff --git a/client/http/doc.go b/client/http/doc.go index 26b3c42..e246c41 100644 --- a/client/http/doc.go +++ b/client/http/doc.go @@ -13,9 +13,9 @@ Example: "context" "encoding/hex" - "github.com/drand/drand/client" - "github.com/drand/drand/client/http" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/client" + "github.com/drand/drand/v2/client/http" + "github.com/drand/drand/v2/common/log" ) var urls = []string{ diff --git a/client/http/http.go b/client/http/http.go index 2ea6b5e..d10109b 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -13,10 +13,10 @@ import ( client2 "github.com/drand/drand-cli/client" - "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" json "github.com/nikkolasg/hexjson" ) diff --git a/client/http/http_test.go b/client/http/http_test.go index ab2141a..f3eef99 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -8,13 +8,13 @@ import ( "testing" "time" + "github.com/drand/drand/v2/common/log" clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/test/http/mock" - "github.com/drand/drand/common/testlogger" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/crypto" ) func TestHTTPClient(t *testing.T) { @@ -30,7 +30,7 @@ func TestHTTPClient(t *testing.T) { t.Fatal(err) } - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) if err != nil { t.Fatal(err) @@ -74,7 +74,7 @@ func TestHTTPGetLatest(t *testing.T) { t.Fatal(err) } - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) if err != nil { t.Fatal(err) @@ -113,7 +113,7 @@ func TestForURLsCreation(t *testing.T) { t.Fatal(err) } - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) clients := ForURLs(ctx, l, []string{"http://invalid.domain/", "http://" + addr}, chainInfo.Hash()) if len(clients) != 2 { t.Fatal("expect both urls returned") @@ -139,7 +139,7 @@ func TestHTTPWatch(t *testing.T) { t.Fatal(err) } - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) if err != nil { t.Fatal(err) @@ -174,7 +174,7 @@ func TestHTTPClientClose(t *testing.T) { t.Fatal(err) } - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) httpClient, err := New(ctx, l, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) if err != nil { t.Fatal(err) diff --git a/client/http/metric.go b/client/http/metric.go index af8aa31..c46564d 100644 --- a/client/http/metric.go +++ b/client/http/metric.go @@ -3,10 +3,11 @@ package http import ( "context" "fmt" - "github.com/drand/drand/common" "time" - chain2 "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common" + + chain2 "github.com/drand/drand/v2/common/client" ) // MeasureHeartbeats periodically tracks latency observed on a set of HTTP clients @@ -32,13 +33,14 @@ const HeartbeatInterval = 10 * time.Second // TODO add metrics back in func (c *HealthMetrics) startObserve(ctx context.Context) { + // we check all clients within HeartbeatInterval + interval := time.Duration(int64(HeartbeatInterval) / int64(len(c.clients))) for { - select { - case <-ctx.Done(): + // check if ctx is Done + if ctx.Err() != nil { return - default: } - time.Sleep(time.Duration(int64(HeartbeatInterval) / int64(len(c.clients)))) + time.Sleep(interval) n := c.next % len(c.clients) httpClient, ok := c.clients[n].(*httpClient) diff --git a/client/lp2p/client.go b/client/lp2p/client.go index 425dfdd..9407ca0 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -14,10 +14,10 @@ import ( "google.golang.org/protobuf/proto" client2 "github.com/drand/drand-cli/client" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/protobuf/drand" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/protobuf/drand" ) // Client is a concrete pubsub client implementation diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index 19e4ff5..6df3324 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common/client" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" @@ -13,7 +13,7 @@ import ( // //func TestGRPCClientTestFunc(t *testing.T) { -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // // start mock drand node // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) @@ -111,7 +111,7 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { // } // // ctx := context.Background() -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // @@ -176,7 +176,7 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { // if err != nil { // return nil, err // } -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) // if err != nil { // return nil, err diff --git a/client/lp2p/doc.go b/client/lp2p/doc.go index 91c5597..140505f 100644 --- a/client/lp2p/doc.go +++ b/client/lp2p/doc.go @@ -5,12 +5,11 @@ randomness by subscribing to a libp2p pubsub topic. WARNING: this client can only be used to "Watch" for new randomness rounds and "Get" randomness rounds it has previously seen that are still in the cache. -If you need to "Get" arbitrary rounds from the chain then you must combine this client with the http or grpc clients. +If you need to "Get" arbitrary rounds from the chain then you must combine this client with the http client. The agnostic client builder must receive "WithChainInfo()" in order for it to validate randomness rounds it receives, or "WithChainHash()" and be combined -with the HTTP or gRPC client implementations so that chain information can be -fetched from them. +with the HTTP client implementations so that chain information can be fetched from them. It is particularly important that rounds are verified since they can be delivered by any peer in the network. @@ -24,10 +23,10 @@ Example using "WithChainInfo()": clock "github.com/jonboulle/clockwork" pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/drand/drand/client" - gclient "github.com/drand/drand/client/lp2p" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/client" + gclient "github.com/drand/drand/v2/client/lp2p" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/log" ) func main() { @@ -63,10 +62,10 @@ Example using "WithChainHash()" and combining it with a different client: clock "github.com/jonboulle/clockwork" pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/drand/drand/client" - "github.com/drand/drand/client/http" - gclient "github.com/drand/drand/client/lp2p" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/client" + "github.com/drand/drand/v2/client/http" + gclient "github.com/drand/drand/v2/client/lp2p" + "github.com/drand/drand/v2/common/log" ) var urls = []string{ diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go index 98bff0f..67eeec8 100644 --- a/client/lp2p/validator.go +++ b/client/lp2p/validator.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "github.com/drand/drand-cli/client" - commonutils "github.com/drand/drand/common" + commonutils "github.com/drand/drand/v2/common" "time" clock "github.com/jonboulle/clockwork" @@ -12,9 +12,9 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "google.golang.org/protobuf/proto" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/crypto" - "github.com/drand/drand/protobuf/drand" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/crypto" + "github.com/drand/drand/v2/protobuf/drand" ) func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk clock.Clock) pubsub.ValidatorEx { diff --git a/client/lp2p/validator_test.go b/client/lp2p/validator_test.go index 684d780..fad4caa 100644 --- a/client/lp2p/validator_test.go +++ b/client/lp2p/validator_test.go @@ -6,11 +6,13 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/drand/drand/common" - "github.com/drand/drand/common/key" "testing" "time" + "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/key" + "github.com/drand/drand/v2/common/log" + clock "github.com/jonboulle/clockwork" pubsub "github.com/libp2p/go-libp2p-pubsub" pb "github.com/libp2p/go-libp2p-pubsub/pb" @@ -20,10 +22,9 @@ import ( "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/test/cache" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/testlogger" - dcrypto "github.com/drand/drand/crypto" - "github.com/drand/drand/protobuf/drand" + chain2 "github.com/drand/drand/v2/common/chain" + dcrypto "github.com/drand/drand/v2/crypto" + "github.com/drand/drand/v2/protobuf/drand" ) type randomDataWrapper struct { @@ -89,7 +90,7 @@ func fakeChainInfo() *chain2.Info { } func TestRejectsUnmarshalBeaconFailure(t *testing.T) { - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(fakeChainInfo(), nil, &c, clk) @@ -102,7 +103,7 @@ func TestRejectsUnmarshalBeaconFailure(t *testing.T) { } func TestAcceptsWithoutTrustRoot(t *testing.T) { - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(nil, nil, &c, clk) @@ -121,7 +122,7 @@ func TestAcceptsWithoutTrustRoot(t *testing.T) { func TestRejectsFutureBeacons(t *testing.T) { info := fakeChainInfo() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(info, nil, &c, clk) @@ -142,7 +143,7 @@ func TestRejectsFutureBeacons(t *testing.T) { func TestRejectsVerifyBeaconFailure(t *testing.T) { info := fakeChainInfo() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(info, nil, &c, clk) @@ -165,7 +166,7 @@ func TestRejectsVerifyBeaconFailure(t *testing.T) { func TestIgnoresCachedEqualBeacon(t *testing.T) { info := fakeChainInfo() ca := cache.NewMapCache() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClockAt(time.Now()) validate := randomnessValidator(info, ca, &c, clk) rdata := fakeRandomData(info, clk) @@ -193,7 +194,7 @@ func TestIgnoresCachedEqualBeacon(t *testing.T) { func TestRejectsCachedUnequalBeacon(t *testing.T) { info := fakeChainInfo() ca := cache.NewMapCache() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(info, ca, &c, clk) rdata := fakeRandomData(info, clk) @@ -224,7 +225,7 @@ func TestRejectsCachedUnequalBeacon(t *testing.T) { func TestIgnoresCachedEqualNonRandomDataBeacon(t *testing.T) { info := fakeChainInfo() ca := cache.NewMapCache() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClockAt(time.Now()) validate := randomnessValidator(info, ca, &c, clk) rdata := randomDataWrapper{fakeRandomData(info, clk)} @@ -252,7 +253,7 @@ func TestIgnoresCachedEqualNonRandomDataBeacon(t *testing.T) { func TestRejectsCachedEqualNonRandomDataBeacon(t *testing.T) { info := fakeChainInfo() ca := cache.NewMapCache() - c := Client{log: testlogger.New(t)} + c := Client{log: log.New(nil, log.DebugLevel, true)} clk := clock.NewFakeClock() validate := randomnessValidator(info, ca, &c, clk) rdata := randomDataWrapper{fakeRandomData(info, clk)} diff --git a/client/mock/mock.go b/client/mock/mock.go index ccd8e25..d1225f1 100644 --- a/client/mock/mock.go +++ b/client/mock/mock.go @@ -7,9 +7,9 @@ import ( "time" "github.com/drand/drand-cli/client/test/result/mock" - commonutils "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" + commonutils "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" ) // Client provide a mocked client interface diff --git a/client/optimizing.go b/client/optimizing.go index 08ac0e4..db45fc5 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -12,10 +12,10 @@ import ( "github.com/hashicorp/go-multierror" - "github.com/drand/drand/common" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) const ( diff --git a/client/optimizing_test.go b/client/optimizing_test.go index a956cd7..69566d4 100644 --- a/client/optimizing_test.go +++ b/client/optimizing_test.go @@ -8,8 +8,8 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) // waitForSpeedTest waits until all clients have had their initial speed test. @@ -71,7 +71,7 @@ func TestOptimizingGet(t *testing.T) { c0.Delay = time.Millisecond * 100 c1.Delay = time.Millisecond - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{c0, c1}, time.Second*5, 2, time.Minute*5, 0) if err != nil { t.Fatal(err) @@ -102,7 +102,7 @@ func TestOptimizingWatch(t *testing.T) { c0.Delay = time.Millisecond - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{c0, c1, c2}, time.Second*5, 2, time.Minute*5, 0) if err != nil { t.Fatal(err) @@ -145,7 +145,7 @@ func TestOptimizingWatchRetryOnClose(t *testing.T) { }, } - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{c}, 0, 0, 0, time.Millisecond) if err != nil { t.Fatal(err) @@ -197,7 +197,7 @@ func TestOptimizingWatchFailover(t *testing.T) { WatchF: wf, } - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{clientMock.ClientWithInfo(chainInfo), c1, c2}, 0, 0, 0, time.Millisecond) if err != nil { t.Fatal(err) @@ -225,7 +225,7 @@ func TestOptimizingWatchFailover(t *testing.T) { } func TestOptimizingRequiresClients(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) _, err := newOptimizingClient(lg, []client.Client{}, 0, 0, 0, 0) if err == nil { t.Fatal("expected err is nil but it shouldn't be") @@ -236,7 +236,7 @@ func TestOptimizingRequiresClients(t *testing.T) { } func TestOptimizingIsLogging(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) if err != nil { t.Fatal(err) @@ -245,7 +245,7 @@ func TestOptimizingIsLogging(t *testing.T) { } func TestOptimizingIsCloser(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) if err != nil { t.Fatal(err) @@ -258,7 +258,7 @@ func TestOptimizingIsCloser(t *testing.T) { } func TestOptimizingInfo(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) chainInfo := fakeChainInfo(t) oc, err := newOptimizingClient(lg, []client.Client{clientMock.ClientWithInfo(chainInfo)}, 0, 0, 0, 0) if err != nil { @@ -275,7 +275,7 @@ func TestOptimizingInfo(t *testing.T) { } func TestOptimizingRoundAt(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, []client.Client{&clientMock.Client{}}, 0, 0, 0, 0) if err != nil { t.Fatal(err) @@ -302,7 +302,7 @@ func TestOptimizingClose(t *testing.T) { wg.Add(len(clients)) - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) oc, err := newOptimizingClient(lg, clients, 0, 0, 0, 0) if err != nil { t.Fatal(err) diff --git a/client/poll.go b/client/poll.go index 2dabf24..d9a90d5 100644 --- a/client/poll.go +++ b/client/poll.go @@ -4,10 +4,10 @@ import ( "context" "time" - commonutils "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + commonutils "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) // PollingWatcher generalizes the `Watch` interface for clients which learn new values diff --git a/client/test/cache/cache.go b/client/test/cache/cache.go index e2016c4..8104126 100644 --- a/client/test/cache/cache.go +++ b/client/test/cache/cache.go @@ -3,7 +3,7 @@ package cache import ( "sync" - "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common/client" ) // MapCache is a simple cache that stores data in memory. diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 5e2de42..2896733 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -8,17 +8,17 @@ import ( "time" localClient "github.com/drand/drand-cli/client" - "github.com/drand/drand/common" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - dhttp "github.com/drand/drand/handler/http" - "github.com/drand/drand/protobuf/drand" - "github.com/drand/drand/test/mock" + "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + dhttp "github.com/drand/drand/v2/handler/http" + "github.com/drand/drand/v2/protobuf/drand" + "github.com/drand/drand/v2/test/mock" clock "github.com/jonboulle/clockwork" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/crypto" ) // NewMockHTTPPublicServer creates a mock drand HTTP server for testing. diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index e5dcdf1..ba15978 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/crypto" "github.com/drand/kyber/share" "github.com/drand/kyber/sign/tbls" "github.com/drand/kyber/util/random" diff --git a/client/utils_test.go b/client/utils_test.go index c0dcebc..8ee8631 100644 --- a/client/utils_test.go +++ b/client/utils_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/key" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/key" + "github.com/drand/drand/v2/crypto" ) // fakeChainInfo creates a chain info object for use in tests. diff --git a/client/verify.go b/client/verify.go index 7040896..304a0b1 100644 --- a/client/verify.go +++ b/client/verify.go @@ -5,11 +5,11 @@ import ( "fmt" "sync" - "github.com/drand/drand/common" - chain2 "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" ) type verifyingClient struct { diff --git a/client/verify_test.go b/client/verify_test.go index 26d337c..cb2dec0 100644 --- a/client/verify_test.go +++ b/client/verify_test.go @@ -10,10 +10,9 @@ import ( client2 "github.com/drand/drand-cli/client" clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/common/testlogger" - "github.com/drand/drand/crypto" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" ) func mockClientWithVerifiableResults(ctx context.Context, t *testing.T, l log.Logger, n int, strictRounds bool) (client.Client, []mock.Result) { @@ -49,7 +48,7 @@ func TestVerifyWithOldVerifiedResult(t *testing.T) { func VerifyFuncTest(t *testing.T, clients, upTo int) { ctx := context.Background() - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) c, results := mockClientWithVerifiableResults(ctx, t, l, clients, true) res, err := c.Get(context.Background(), results[upTo].GetRound()) @@ -62,7 +61,7 @@ func VerifyFuncTest(t *testing.T, clients, upTo int) { func TestGetWithRoundMismatch(t *testing.T) { ctx := context.Background() - l := testlogger.New(t) + l := log.New(nil, log.DebugLevel, true) c, results := mockClientWithVerifiableResults(ctx, t, l, 5, false) for i := 1; i < len(results); i++ { results[i] = results[0] diff --git a/client/watcher.go b/client/watcher.go index 5ccf6bc..3c6a96d 100644 --- a/client/watcher.go +++ b/client/watcher.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/go-multierror" - "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common/client" ) type watcherClient struct { diff --git a/client/watcher_test.go b/client/watcher_test.go index 50be389..6b47640 100644 --- a/client/watcher_test.go +++ b/client/watcher_test.go @@ -8,7 +8,7 @@ import ( clientMock "github.com/drand/drand-cli/client/mock" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/client" + "github.com/drand/drand/v2/common/client" ) func TestWatcherWatch(t *testing.T) { diff --git a/go.mod b/go.mod index 8a5015f..8798a6a 100644 --- a/go.mod +++ b/go.mod @@ -1,107 +1,96 @@ module github.com/drand/drand-cli -go 1.20 +go 1.21 + +toolchain go1.22.2 require ( - github.com/BurntSushi/toml v1.3.2 - github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 - github.com/drand/kyber v1.2.0 - github.com/google/uuid v1.3.1 - github.com/gorilla/handlers v1.5.1 + github.com/BurntSushi/toml v1.4.0 + github.com/drand/drand/v2 v2.0.6-testnet + github.com/drand/kyber v1.3.1 + github.com/google/uuid v1.6.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 - github.com/libp2p/go-libp2p v0.31.0 - github.com/libp2p/go-libp2p-pubsub v0.9.3 - github.com/multiformats/go-multiaddr v0.11.0 + github.com/libp2p/go-libp2p v0.34.1 + github.com/libp2p/go-libp2p-pubsub v0.11.0 + github.com/multiformats/go-multiaddr v0.12.4 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.16.0 - github.com/stretchr/testify v1.8.4 - github.com/urfave/cli/v2 v2.25.7 - golang.org/x/crypto v0.14.0 - google.golang.org/grpc v1.57.0 - google.golang.org/protobuf v1.31.0 + github.com/prometheus/client_golang v1.19.1 + github.com/stretchr/testify v1.9.0 + github.com/urfave/cli/v2 v2.27.2 + golang.org/x/crypto v0.23.0 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.34.1 ) require ( - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect - github.com/ardanlabs/darwin/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/drand/kyber-bls12381 v0.3.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/elastic/gosigar v0.14.2 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/elastic/gosigar v0.14.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-chi/chi v1.5.4 // 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.4 // indirect + github.com/go-chi/chi/v5 v5.0.12 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/gogo/status v1.1.1 // indirect - github.com/golang/glog v1.1.2 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/glog v1.2.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230901174712-0191c66da455 // indirect - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/golang-lru/arc/v2 v2.0.6 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect + github.com/hashicorp/golang-lru/arc/v2 v2.0.7 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/go-cid v0.4.1 // 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/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/lib/pq v1.10.9 // 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.3.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.59 // 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.1 // indirect @@ -112,59 +101,62 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.12.0 // indirect - github.com/opencontainers/runtime-spec v1.1.0 // indirect - github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect - github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.18.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pion/datachannel v1.5.6 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/ice/v2 v2.3.24 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.40 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.53.0 // indirect + github.com/prometheus/procfs v0.15.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.4 // indirect - github.com/quic-go/quic-go v0.38.1 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sercand/kuberesolver/v4 v4.0.0 // indirect - github.com/sirupsen/logrus v1.9.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect - github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5 // indirect - github.com/weaveworks/promrus v1.2.0 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.etcd.io/bbolt v1.3.7 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 // indirect - go.opentelemetry.io/otel v1.17.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.17.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.17.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.20.0 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + go.etcd.io/bbolt v1.3.10 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect + go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/sdk v1.27.0 // indirect + go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.21.1 // indirect + go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + golang.org/x/tools v0.21.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index d7ba72d..06af342 100644 --- a/go.sum +++ b/go.sum @@ -2,465 +2,47 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT 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= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -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.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -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/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -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/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -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.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -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/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -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/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -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/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -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.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -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/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -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.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -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/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -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/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -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/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -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/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -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.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -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/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -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= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfKxvSy1HMhoes= 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= 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/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/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= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -469,24 +51,24 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= +github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= @@ -499,240 +81,116 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7 h1:IEW/xLeyaufieO8ZpEynnyMMMYNPcqD4zA1q1ZUiOV0= -github.com/drand/drand v1.5.9-0.20231205130709-881d056487b7/go.mod h1:TzheRfrx2IkjJxF2tjiyXmtCWmkifD+GxATU3Tq/81E= -github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= -github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xtwfo= +github.com/drand/drand/v2 v2.0.6-testnet h1:l/wx6as7LER+idrKTbENnuwB/DyFBcATNpXrEr0wwHY= +github.com/drand/drand/v2 v2.0.6-testnet/go.mod h1:4Dzpn1uQMlFs7vmoO3jGF3QL7WY6btmyeWi8ife/CJg= +github.com/drand/kyber v1.3.1 h1:E0p6M3II+loMVwTlAp5zu4+GGZFNiRfq02qZxzw2T+Y= +github.com/drand/kyber v1.3.1/go.mod h1:f+mNHjiGT++CuueBrpeMhFNdKZAsy0tu03bKq9D5LPA= github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= +github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= 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/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= 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/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -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.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 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= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= -github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= -github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= -github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -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/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/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= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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-20230901174712-0191c66da455 h1:YhRUmI1ttDC4sxKY2V62BTI8hCXnyZBV9h38eAanInE= -github.com/google/pprof v0.0.0-20230901174712-0191c66da455/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 h1:r6YdmbD41tGHeCWDyHF691LWtL7D1iSTyJaKejTWwVU= +github.com/google/pprof v0.0.0-20240521024322-9665fa269a30/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= 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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -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/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -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.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 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.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/arc/v2 v2.0.6 h1:4NU7uP5vSoK6TbaMj3NtY478TTAWLso/vL1gpNrInHg= -github.com/hashicorp/golang-lru/arc/v2 v2.0.6/go.mod h1:cfdDIX05DWvYV6/shsxDfa/OVcRieOt+q4FnM8x+Xno= -github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= -github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/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.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -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= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= @@ -742,9 +200,11 @@ github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= +github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg= 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-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= @@ -757,62 +217,49 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= -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.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/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= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 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.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -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= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -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.31.0 h1:LFShhP8F6xthWiBBq3euxbKjZsoRajVEyBS9snfHxYg= -github.com/libp2p/go-libp2p v0.31.0/go.mod h1:W/FEK1c/t04PbRH3fA9i5oucu5YcgrG0JVoBWT1B7Eg= -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.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= -github.com/libp2p/go-libp2p-pubsub v0.9.3/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc= +github.com/libp2p/go-libp2p v0.34.1 h1:fxn9vyLo7vJcXQRNvdRbyPjbzuQgi2UiqC8hEbn8a18= +github.com/libp2p/go-libp2p v0.34.1/go.mod h1:snyJQix4ET6Tj+LeI0VPjjxTtdWpeOhYt5lEY0KirkQ= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= +github.com/libp2p/go-libp2p-pubsub v0.11.0/go.mod h1:QEb+hEV9WL9wCiUAnpY29FZR6W3zK8qYlaml8R4q6gQ= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= @@ -824,27 +271,20 @@ github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8S github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= 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/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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= 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= @@ -857,11 +297,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 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/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/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= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -871,8 +308,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10= -github.com/multiformats/go-multiaddr v0.11.0/go.mod h1:gWUm0QLR4thQ6+ZF6SXUw8YjtwQSPapICM+NmCkxHSM= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -884,100 +321,104 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -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-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= 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= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -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.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= -github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/ginkgo/v2 v2.18.0 h1:W9Y7IWXxPUpAit9ieMOLI7PJZGaW22DTKgiVAuhDTLc= +github.com/onsi/ginkgo/v2 v2.18.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= -github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= -github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/exporter-toolkit v0.8.2/go.mod h1:00shzmJL7KxcsabLWcONwpyNEuWhREOnFqZW7vadFS0= +github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= +github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= 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= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= +github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= 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-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= -github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE= -github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= 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.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sercand/kuberesolver/v4 v4.0.0 h1:frL7laPDG/lFm5n98ODmWnn+cvPpzlkf3LhzuPhcHP4= -github.com/sercand/kuberesolver/v4 v4.0.0/go.mod h1:F4RGyuRmMAjeXHKL+w4P7AwUnPceEAPAhxUgXZjKgvM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -1002,22 +443,14 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= -github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= 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/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= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -1026,92 +459,70 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 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= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -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/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= 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-20230728070032-dd9e68f319d5 h1:nORobjToZAvi54wcuUXLq+XG2Rsr0XEizy5aHBHvqWQ= -github.com/weaveworks/common v0.0.0-20230728070032-dd9e68f319d5/go.mod h1:rgbeLfJUtEr+G74cwFPR1k/4N0kDeaeSv/qhUNE4hm8= -github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= -github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -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.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0 h1:HKORGpiOY0R0nAPtKx/ub8/7XoHhRooP8yNRkuPfelI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.43.0/go.mod h1:e+y1M74SYXo/FcIx3UATwth2+5dDkM8dBi7eXg1tbw8= -go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= -go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= -go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= -go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= -go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= +go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= +go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= +go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= +go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= +go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= -go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= +go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -1119,168 +530,78 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/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-20211108221036-ceb1ce70b4fa/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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -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/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -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-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -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/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= 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= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= 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-20210813160813-60bc85c4be6d/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= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -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.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= 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= @@ -1288,483 +609,140 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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-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= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -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/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -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= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -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/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/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -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= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -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-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-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230807174057-1744710a1577 h1:Tyk/35yqszRCvaragTn5NnkY6IiKk/XvHzEWepo71N0= -google.golang.org/genproto v0.0.0-20230807174057-1744710a1577/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577 h1:xv8KoglAClYGkprUSmDTKaILtzfD8XzG9NYVXMprjKo= -google.golang.org/genproto/googleapis/api v0.0.0-20230807174057-1744710a1577/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e h1:SkdGTrROJl2jRGT/Fxv5QUf9jtdKCQh4KQJXbXVLAi0= +google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e/go.mod h1:LweJcLbyVij6rCex8YunD8DYR5VDonap/jYl3ZRxcIU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e h1:Elxv5MwEkCI9f5SkoL6afed6NTdxaGoAo39eANBwHL8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= 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.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -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/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1773,16 +751,9 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd 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= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -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= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/gossip-relay/README.md b/gossip-relay/README.md index 282c320..07a3b50 100644 --- a/gossip-relay/README.md +++ b/gossip-relay/README.md @@ -177,8 +177,8 @@ import ( "github.com/drand/drand-cli/client" p2pClient "github.com/drand/drand-cli/client/lp2p" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/log" ) const ( @@ -235,7 +235,7 @@ import ( "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/http" gclient "github.com/drand/drand-cli/client/lp2p" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/log" ) const ( diff --git a/gossip-relay/main.go b/gossip-relay/main.go index 64fce2e..ddd7366 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -11,7 +11,7 @@ import ( "github.com/drand/drand-cli/internal/lib" "github.com/drand/drand-cli/internal/lp2p" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/log" ) // Automatically set through -ldflags diff --git a/http-relay/main.go b/http-relay/main.go deleted file mode 100644 index 8e0d002..0000000 --- a/http-relay/main.go +++ /dev/null @@ -1,209 +0,0 @@ -package main - -import ( - "context" - "encoding/hex" - "fmt" - "net" - "net/http" - "net/http/httptest" - "os" - - "github.com/gorilla/handlers" - "github.com/urfave/cli/v2" - - "github.com/drand/drand-cli/internal/lib" - common2 "github.com/drand/drand/common" - "github.com/drand/drand/common/log" - dhttp "github.com/drand/drand/handler/http" -) - -// Automatically set through -ldflags -// Example: go install -ldflags "-X main.buildDate=`date -u +%d/%m/%Y@%H:%M:%S` -X main.gitCommit=`git rev-parse HEAD`" -var ( - gitCommit = "none" - buildDate = "unknown" -) - -const accessLogPermFolder = 0o666 - -var accessLogFlag = &cli.StringFlag{ - Name: "access-log", - Usage: "file to log http-relay accesses to", - EnvVars: []string{"DRAND_RELAY_ACCESS_LOG"}, -} - -var listenFlag = &cli.StringFlag{ - Name: "bind", - Usage: "local host:port to bind the listener", - EnvVars: []string{"DRAND_RELAY_BIND"}, -} - -var metricsFlag = &cli.StringFlag{ - Name: "metrics", - Usage: "local host:port to bind a metrics servlet (optional)", - 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: "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, -} - -// Relay a GRPC connection to an HTTP server. -// -//nolint:gocyclo,funlen -func Relay(c *cli.Context) error { - //tracesProbability := 0.05 - //if c.IsSet(tracesProbabilityFlag.Name) { - // tracesProbability = c.Float64(tracesProbabilityFlag.Name) - //} - // - //_, tracerShutdown := metrics.InitTracer("drand_relay", c.String(tracesFlag.Name), tracesProbability) - //defer tracerShutdown(c.Context) - - version := "2.0.0" - - //if c.IsSet(metricsFlag.Name) { - // metricsListener := metrics.Start(cliLog, c.String(metricsFlag.Name), pprof.WithProfile(), nil) - // defer metricsListener.Close() - // - // if err := metrics.PrivateMetrics.Register(grpcprometheus.DefaultClientMetrics); err != nil { - // return err - // } - //} - - hashFlagSet := c.IsSet(lib.HashFlag.Name) - if hashFlagSet { - return fmt.Errorf("--%s is deprecated on relay http-relay, please use %s instead", lib.HashFlag.Name, lib.HashListFlag.Name) - } - - handler, err := dhttp.New(context.Background(), fmt.Sprintf("drand/%s (%s)", - version, gitCommit)) - if err != nil { - return fmt.Errorf("failed to create rest handler: %w", err) - } - - hashesMap := make(map[string]bool) - if c.IsSet(lib.HashListFlag.Name) { - hashesList := c.StringSlice(lib.HashListFlag.Name) - for _, hash := range hashesList { - hashesMap[hash] = true - } - } else { - hashesMap[common2.DefaultChainHash] = true - } - - skipHashes := make(map[string]bool) - for hash := range hashesMap { - // todo: don't reuse 'c' - if hash != common2.DefaultChainHash { - if _, err := hex.DecodeString(hash); err != nil { - return fmt.Errorf("failed to decode chain hash value: %w", err) - } - if err := c.Set(lib.HashFlag.Name, hash); err != nil { - return fmt.Errorf("failed to initiate chain hash handler: %w", err) - } - } else { - if err := c.Set(lib.HashFlag.Name, ""); err != nil { - return fmt.Errorf("failed to initiate default chain hash handler: %w", err) - } - } - - subCli, err := lib.Create(c, c.IsSet(metricsFlag.Name)) - if err != nil { - log.DefaultLogger().Warnw("failed to create client", "hash", hash, "error", err) - skipHashes[hash] = true - continue - } - - handler.RegisterNewBeaconHandler(subCli, hash) - } - - if len(skipHashes) == len(hashesMap) { - return fmt.Errorf("failed to create any beacon handlers") - } - - if c.IsSet(accessLogFlag.Name) { - logFile, err := os.OpenFile(c.String(accessLogFlag.Name), os.O_CREATE|os.O_APPEND|os.O_WRONLY, accessLogPermFolder) - if err != nil { - return fmt.Errorf("failed to open access log: %w", err) - } - defer logFile.Close() - handler.SetHTTPHandler(handlers.CombinedLoggingHandler(logFile, handler.GetHTTPHandler())) - } else { - handler.SetHTTPHandler(handlers.CombinedLoggingHandler(os.Stdout, handler.GetHTTPHandler())) - } - - bind := "127.0.0.1:0" - if c.IsSet(listenFlag.Name) { - bind = c.String(listenFlag.Name) - } - listener, err := net.Listen("tcp", bind) - if err != nil { - return err - } - - // jumpstart bootup - for hash := range hashesMap { - if skipHashes[hash] { - continue - } - - req, _ := http.NewRequest(http.MethodGet, "/public/0", http.NoBody) - if hash != common2.DefaultChainHash { - req, _ = http.NewRequest(http.MethodGet, fmt.Sprintf("/%s/public/0", hash), http.NoBody) - } - - rr := httptest.NewRecorder() - handler.GetHTTPHandler().ServeHTTP(rr, req) - if rr.Code != http.StatusOK { - log.DefaultLogger().Warnw("", "binary", "relay", "chain-hash", hash, "startup failed", rr.Code) - } - } - - fmt.Printf("Listening at %s\n", listener.Addr()) - // http-relay.Serve is marked as problematic because it does not - // have tweaked timeouts out of the box. - - //nolint - return http.Serve(listener, handler.GetHTTPHandler()) -} - -func main() { - version := common2.GetAppVersion() - lg := log.New(nil, log.DefaultLevel, false) - - app := &cli.App{ - 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, tracesFlag, tracesProbabilityFlag), - Action: func(ctx *cli.Context) error { - ctx.Context = log.ToContext(ctx.Context, lg) - return Relay(ctx) - }, - } - - // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. - app.EnableBashCompletion = true - - cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("drand HTTP relay %v (date %v, commit %v)\n", version, buildDate, gitCommit) - } - - err := app.Run(os.Args) - if err != nil { - lg.Fatalw("", "binary", "relay", "err", err) - } -} diff --git a/internal/cli.go b/internal/cli.go index f8e12b4..5ada1c2 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -6,7 +6,7 @@ import ( "github.com/urfave/cli/v2" - "github.com/drand/drand/common" + "github.com/drand/drand/v2/common" ) // Automatically set through -ldflags @@ -24,27 +24,20 @@ var verboseFlag = &cli.BoolFlag{ EnvVars: []string{"DRAND_VERBOSE"}, } -var nodeFlag = &cli.StringFlag{ - Name: "nodes", - Usage: "Contact the nodes at the given list of whitespace-separated addresses which have to be present in group.toml.", - EnvVars: []string{"DRAND_NODES"}, +var relayFlag = &cli.StringSliceFlag{ + Name: "relays", + Usage: "Contact the HTTP relay at the given URL address. Can be specified multiple times to try multiple relays.", + EnvVars: []string{"DRAND_HTTP_RELAY"}, } var roundFlag = &cli.IntFlag{ Name: "round", - Usage: "Request the public randomness generated at round num. If the drand beacon does not have the requested value," + - " it returns an error. If not specified, the current randomness is returned.", + Usage: "Request the public randomness generated at round num. If the requested value doesn't exist yet," + + " it returns an error. If not specified or 0, the latest beacon is returned.", EnvVars: []string{"DRAND_ROUND"}, } -var hashOnly = &cli.BoolFlag{ - Name: "hash", - Usage: "Only print the hash of the group file", - EnvVars: []string{"DRAND_HASH"}, -} - -// TODO (DLSNIPER): This is a duplicate of the hashInfoReq. Should these be merged into a single flag? -var hashInfoNoReq = &cli.StringFlag{ +var hashInfoFlag = &cli.StringFlag{ Name: "chain-hash", Usage: "The hash of the chain info", EnvVars: []string{"DRAND_CHAIN_HASH"}, @@ -78,14 +71,14 @@ var appCommands = []*cli.Command{ "beacon via TLS and falls back to plaintext communication " + "if the contacted node has not activated TLS in which case " + "it prints a warning.\n", - Flags: toArray(roundFlag, nodeFlag), + Flags: toArray(roundFlag, relayFlag, jsonFlag), Action: getPublicRandomness, }, { Name: "chain-info", Usage: "Get the binding chain information that this node participates to", ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.", - Flags: toArray(hashOnly, hashInfoNoReq), + Flags: toArray(hashInfoFlag, relayFlag, jsonFlag), Action: getChainInfo, }, }, @@ -97,7 +90,7 @@ func CLI() *cli.App { version := common.GetAppVersion() app := cli.NewApp() - app.Name = "drand" + app.Name = "drand-client" // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. app.EnableBashCompletion = true diff --git a/internal/cli_test.go b/internal/cli_test.go index 27fcbc0..47f6109 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -28,12 +28,11 @@ package drand // "github.com/drand/drand-cli/internal/fs" // "github.com/drand/drand-cli/internal/net" // "github.com/drand/drand-cli/internal/test" -// "github.com/drand/drand/common/testlogger" -// "github.com/drand/drand/common" -// chain2 "github.com/drand/drand/common/chain" -// "github.com/drand/drand/common/key" -// "github.com/drand/drand/common/log" -// "github.com/drand/drand/crypto" +// "github.com/drand/drand/v2/common" +// chain2 "github.com/drand/drand/v2/common/chain" +// "github.com/drand/drand/v2/common/key" +// "github.com/drand/drand/v2/common/log" +// "github.com/drand/drand/v2/crypto" // "github.com/drand/kyber" // "github.com/drand/kyber/share" // "github.com/drand/kyber/share/dkg" @@ -64,7 +63,7 @@ package drand // //func TestDeleteBeacon(t *testing.T) { // beaconID := test.GetBeaconIDFromEnv() -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // ctx := context.Background() // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) @@ -136,7 +135,7 @@ package drand // //func TestKeySelfSign(t *testing.T) { // beaconID := test.GetBeaconIDFromEnv() -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // // tmp := path.Join(t.TempDir(), "drand") // @@ -173,7 +172,7 @@ package drand // //func TestKeyGen(t *testing.T) { // beaconID := test.GetBeaconIDFromEnv() -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // // tmp := path.Join(t.TempDir(), "drand") // sch, _ := crypto.GetSchemeFromEnv() @@ -325,7 +324,7 @@ package drand // ////nolint:funlen //func TestStartWithoutGroup(t *testing.T) { -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -478,7 +477,7 @@ package drand // //func testStartedDrandFunctional(t *testing.T, ctrlPort, rootPath, address string, group *key.Group, fileStore key.Store, beaconID string) { // t.Helper() -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // // testPing(t, ctrlPort) // testStatus(t, ctrlPort, beaconID) @@ -589,7 +588,7 @@ package drand ////nolint:funlen //This is a test //func TestClientTLS(t *testing.T) { // t.Skip("The test fails because the logic for generating the group has changed") -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -683,7 +682,7 @@ package drand // //func testStartedTLSDrandFunctional(t *testing.T, ctrlPort, certPath string, group *key.Group, priv *key.Pair) { // t.Helper() -// lg := testlogger.New(t) +// lg := log.New(nil, log.DebugLevel, true) // // var err error // @@ -755,7 +754,7 @@ package drand // t.Skip("skipping test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -822,7 +821,7 @@ package drand // t.Skip("skipping test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -934,7 +933,7 @@ package drand // t.Skip("skipping slow test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -1008,7 +1007,7 @@ package drand // t.Skip("skipping slow test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -1299,7 +1298,7 @@ package drand // // certsDir := path.Join(tmpPath, "certs") // require.NoError(t, os.Mkdir(certsDir, 0o740)) -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // // ins := make([]*drandInstance, 0, n) // for i := 1; i <= n; i++ { @@ -1364,7 +1363,7 @@ package drand // t.Skip("skipping test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() @@ -1465,7 +1464,7 @@ package drand // t.Skip("skipping test in short mode.") // } // -// l := testlogger.New(t) +// l := log.New(nil, log.DebugLevel, true) // sch, err := crypto.GetSchemeFromEnv() // require.NoError(t, err) // beaconID := test.GetBeaconIDFromEnv() diff --git a/client/grpc/client.go b/internal/grpc/client.go similarity index 91% rename from client/grpc/client.go rename to internal/grpc/client.go index a748ffd..47396f5 100644 --- a/client/grpc/client.go +++ b/internal/grpc/client.go @@ -13,12 +13,11 @@ import ( grpcInsec "google.golang.org/grpc/credentials/insecure" localClient "github.com/drand/drand-cli/client" - commonutils "github.com/drand/drand/common" - "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/protobuf/common" - "github.com/drand/drand/protobuf/drand" + commonutils "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/protobuf/drand" ) const grpcDefaultTimeout = 5 * time.Second @@ -116,8 +115,8 @@ func (g *grpcClient) translate(stream drand.Public_PublicRandStreamClient, out c } } -func (g *grpcClient) getMetadata() *common.Metadata { - return &common.Metadata{ChainHash: g.chainHash} +func (g *grpcClient) getMetadata() *drand.Metadata { + return &drand.Metadata{ChainHash: g.chainHash} } func (g *grpcClient) RoundAt(t time.Time) uint64 { diff --git a/client/grpc/client_test.go b/internal/grpc/client_test.go similarity index 95% rename from client/grpc/client_test.go rename to internal/grpc/client_test.go index 2833322..113e8a8 100644 --- a/client/grpc/client_test.go +++ b/internal/grpc/client_test.go @@ -3,7 +3,7 @@ package grpc import ( "bytes" "context" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/log" clock "github.com/jonboulle/clockwork" "sync" "testing" @@ -13,8 +13,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/drand/drand/crypto" - "github.com/drand/drand/test/mock" + "github.com/drand/drand/v2/crypto" + "github.com/drand/drand/v2/test/mock" ) func TestClient(t *testing.T) { diff --git a/client/grpc/doc.go b/internal/grpc/doc.go similarity index 92% rename from client/grpc/doc.go rename to internal/grpc/doc.go index ac6e2fe..f61c586 100644 --- a/client/grpc/doc.go +++ b/internal/grpc/doc.go @@ -12,8 +12,8 @@ Example: import ( "encoding/hex" - "github.com/drand/drand/client" - "github.com/drand/drand/client/grpc" + "github.com/drand/drand/v2/client" + "github.com/drand/drand/v2/client/grpc" ) const ( diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 5128719..a458aae 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -11,7 +11,7 @@ import ( "strings" "github.com/BurntSushi/toml" - "github.com/drand/drand/common/key" + "github.com/drand/drand/v2/common/key" "github.com/google/uuid" bds "github.com/ipfs/go-ds-badger2" clock "github.com/jonboulle/clockwork" @@ -20,14 +20,14 @@ import ( "github.com/urfave/cli/v2" pubClient "github.com/drand/drand-cli/client" - "github.com/drand/drand-cli/client/grpc" http2 "github.com/drand/drand-cli/client/http" gclient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand-cli/internal/grpc" "github.com/drand/drand-cli/internal/lp2p" - commonutils "github.com/drand/drand/common" - chainCommon "github.com/drand/drand/common/chain" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" + commonutils "github.com/drand/drand/v2/common" + chainCommon "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" ) var ( diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index c1ccdee..7c9e68b 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/drand/drand/test/mock" + "github.com/drand/drand/v2/test/mock" clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" @@ -19,10 +19,9 @@ import ( "github.com/drand/drand-cli/client" httpmock "github.com/drand/drand-cli/client/test/http/mock" - commonutils "github.com/drand/drand/common" - "github.com/drand/drand/common/log" - "github.com/drand/drand/common/testlogger" - "github.com/drand/drand/crypto" + commonutils "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" ) var ( @@ -53,7 +52,7 @@ func run(l log.Logger, args []string) error { func TestClientLib(t *testing.T) { opts = []client.Option{} - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) err := run(lg, []string{"mock-client"}) if err == nil { t.Fatal("need to specify a connection method.", err) @@ -107,7 +106,7 @@ func TestClientLib(t *testing.T) { } func TestClientLibGroupConfTOML(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--group-conf", groupTOMLPath()}) if err != nil { t.Fatal(err) @@ -115,7 +114,7 @@ func TestClientLibGroupConfTOML(t *testing.T) { } func TestClientLibGroupConfJSON(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) @@ -140,7 +139,7 @@ func TestClientLibGroupConfJSON(t *testing.T) { } func TestClientLibChainHashOverrideError(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) err := run(lg, []string{ "mock-client", "--relay", @@ -157,7 +156,7 @@ func TestClientLibChainHashOverrideError(t *testing.T) { } func TestClientLibListenPort(t *testing.T) { - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) if err != nil { t.Fatal(err) diff --git a/internal/lp2p/ctor.go b/internal/lp2p/ctor.go index 6655b99..5fb019e 100644 --- a/internal/lp2p/ctor.go +++ b/internal/lp2p/ctor.go @@ -26,7 +26,7 @@ import ( "github.com/pkg/errors" "golang.org/x/crypto/blake2b" - dlog "github.com/drand/drand/common/log" + dlog "github.com/drand/drand/v2/common/log" ) const ( diff --git a/internal/lp2p/ctor_test.go b/internal/lp2p/ctor_test.go index ade369b..0f2e2c4 100644 --- a/internal/lp2p/ctor_test.go +++ b/internal/lp2p/ctor_test.go @@ -2,7 +2,7 @@ package lp2p import ( "fmt" - "github.com/drand/drand/common/log" + "github.com/drand/drand/v2/common/log" "path" "testing" ) diff --git a/internal/lp2p/relaynode.go b/internal/lp2p/relaynode.go index 6f16d28..c8a48e4 100644 --- a/internal/lp2p/relaynode.go +++ b/internal/lp2p/relaynode.go @@ -13,9 +13,9 @@ import ( "google.golang.org/protobuf/proto" client2 "github.com/drand/drand-cli/client" - "github.com/drand/drand/common/client" - "github.com/drand/drand/common/log" - "github.com/drand/drand/protobuf/drand" + "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/protobuf/drand" ) // GossipRelayConfig configures a gossip-relay relay node. diff --git a/internal/lp2p/relaynode_test.go b/internal/lp2p/relaynode_test.go index 0183b17..256ab41 100644 --- a/internal/lp2p/relaynode_test.go +++ b/internal/lp2p/relaynode_test.go @@ -4,19 +4,20 @@ import ( "context" "encoding/hex" "errors" - "github.com/drand/drand/common/key" - "github.com/drand/drand/crypto" - "github.com/stretchr/testify/require" "path" "sync" "testing" "time" + "github.com/drand/drand/v2/common/key" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" + "github.com/stretchr/testify/require" + "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/test/result/mock" - "github.com/drand/drand/common/chain" - client2 "github.com/drand/drand/common/client" - "github.com/drand/drand/common/testlogger" + "github.com/drand/drand/v2/common/chain" + client2 "github.com/drand/drand/v2/common/client" ) type mockClient struct { @@ -98,7 +99,7 @@ func TestWatchRetryOnClose(t *testing.T) { c := &mockClient{chainInfo, watchF} td := t.TempDir() - lg := testlogger.New(t) + lg := log.New(nil, log.DebugLevel, true) gr, err := NewGossipRelayNode(lg, &GossipRelayConfig{ ChainHash: hex.EncodeToString(chainInfo.Hash()), Addr: "/ip4/0.0.0.0/tcp/0", From fc0dd2a49a686706be05930bb80afdf4e4ade01e Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 20 Jun 2024 16:07:09 +0200 Subject: [PATCH 18/28] adding GHA --- .github/workflows/lint.yml | 26 +++++++++ .github/workflows/tests.yaml | 30 +++++++++++ client/http/http.go | 3 -- go.mod | 54 +++++++++---------- go.sum | 100 +++++++++++++++++------------------ 5 files changed, 132 insertions(+), 81 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..6a543b3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,26 @@ +name: Lint + +on: + pull_request: + branches: [ main ] + +concurrency: + group: ci-${{ github.ref }}-lint + cancel-in-progress: true + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Checkout + uses: actions/checkout@v4 + + - name: golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + version: v1.58 + args: --timeout 5m diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..8c25f9a --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,30 @@ +name: "Build/Tests" +on: + push: + branches: + - master + - main + pull_request: + +concurrency: + group: ci-${{ github.ref }}-tests + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + continue-on-error: true + strategy: + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Unit tests + env: + DRAND_TEST_LOGS: "${{ runner.debug == '1' && 'DEBUG' || 'INFO' }}" + CI: "true" + run: go test -v ./... diff --git a/client/http/http.go b/client/http/http.go index d10109b..ce86831 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -50,9 +50,6 @@ func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transp done: make(chan struct{}), } - ctx, cancel := context.WithTimeout(ctx, time.Second) - defer cancel() - chainInfo, err := c.FetchChainInfo(ctx, chainHash) if err != nil { return nil, err diff --git a/go.mod b/go.mod index 8798a6a..0204591 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/drand/drand-cli -go 1.21 - -toolchain go1.22.2 +go 1.22 require ( github.com/BurntSushi/toml v1.4.0 @@ -15,7 +13,7 @@ require ( github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 - github.com/libp2p/go-libp2p v0.34.1 + github.com/libp2p/go-libp2p v0.35.1 github.com/libp2p/go-libp2p-pubsub v0.11.0 github.com/multiformats/go-multiaddr v0.12.4 github.com/multiformats/go-multiaddr-dns v0.3.1 @@ -24,9 +22,9 @@ require ( github.com/prometheus/client_golang v1.19.1 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.2 - golang.org/x/crypto v0.23.0 + golang.org/x/crypto v0.24.0 google.golang.org/grpc v1.64.0 - google.golang.org/protobuf v1.34.1 + google.golang.org/protobuf v1.34.2 ) require ( @@ -51,7 +49,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-chi/chi/v5 v5.0.12 // indirect + github.com/go-chi/chi/v5 v5.0.13 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect @@ -61,8 +59,8 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 // indirect - github.com/gorilla/websocket v1.5.1 // indirect + github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -76,8 +74,8 @@ require ( github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmoiron/sqlx v1.4.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect @@ -90,7 +88,7 @@ require ( github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.59 // indirect + github.com/miekg/dns v1.1.61 // 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.1 // indirect @@ -103,12 +101,12 @@ require ( github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.18.0 // indirect + github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pion/datachannel v1.5.6 // indirect github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.24 // indirect + github.com/pion/ice/v2 v2.3.25 // indirect github.com/pion/interceptor v0.1.29 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect @@ -121,13 +119,13 @@ require ( github.com/pion/stun v0.6.1 // indirect github.com/pion/transport/v2 v2.2.5 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.40 // indirect + github.com/pion/webrtc/v3 v3.2.42 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.15.0 // indirect + github.com/prometheus/common v0.54.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/quic-go v0.45.0 // indirect github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -142,21 +140,21 @@ require ( go.opentelemetry.io/otel/metric v1.27.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect go.opentelemetry.io/otel/trace v1.27.0 // indirect - go.opentelemetry.io/proto/otlp v1.2.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.21.1 // indirect + go.uber.org/fx v1.22.0 // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.21.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.22.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 06af342..f86de90 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD 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/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.13 h1:JlH2F2M8qnwl0N1+JFFzlX9TlKJYas3aPXdiuTmJL+w= +github.com/go-chi/chi/v5 v5.0.13/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -157,8 +157,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240521024322-9665fa269a30 h1:r6YdmbD41tGHeCWDyHF691LWtL7D1iSTyJaKejTWwVU= -github.com/google/pprof v0.0.0-20240521024322-9665fa269a30/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M= +github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 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.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -167,8 +167,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/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.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= @@ -229,10 +229,10 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= @@ -252,8 +252,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 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.34.1 h1:fxn9vyLo7vJcXQRNvdRbyPjbzuQgi2UiqC8hEbn8a18= -github.com/libp2p/go-libp2p v0.34.1/go.mod h1:snyJQix4ET6Tj+LeI0VPjjxTtdWpeOhYt5lEY0KirkQ= +github.com/libp2p/go-libp2p v0.35.1 h1:Hm7Ub2BF+GCb14ojcsEK6WAy5it5smPDK02iXSZLl50= +github.com/libp2p/go-libp2p v0.35.1/go.mod h1:Dnkgba5hsfSv5dvvXC8nfqk44hH0gIKKno+HOMU0fdc= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= @@ -283,8 +283,8 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= 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= @@ -330,8 +330,8 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= 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.18.0 h1:W9Y7IWXxPUpAit9ieMOLI7PJZGaW22DTKgiVAuhDTLc= -github.com/onsi/ginkgo/v2 v2.18.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -347,8 +347,8 @@ github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNI github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= -github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs= +github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -384,8 +384,8 @@ github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37 github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= -github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= +github.com/pion/webrtc/v3 v3.2.42 h1:WN/ZuMjtpQOoGRCZUg/zFG+JHEvYLVyDKOxU6H1qWlE= +github.com/pion/webrtc/v3 v3.2.42/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -399,15 +399,15 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= +github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= +github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= -github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 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/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= -github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE= +github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -509,14 +509,14 @@ go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kT go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= -go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= -go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= -go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= +go.uber.org/fx v1.22.0 h1:pApUK7yL0OUHMd8vkunWSlLxZVFFk70jR2nKde8X2NM= +go.uber.org/fx v1.22.0/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -551,11 +551,11 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= 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= @@ -569,8 +569,8 @@ golang.org/x/mod v0.3.0/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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= @@ -596,8 +596,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -651,8 +651,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -672,8 +672,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -697,8 +697,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= 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= @@ -717,10 +717,10 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e h1:SkdGTrROJl2jRGT/Fxv5QUf9jtdKCQh4KQJXbXVLAi0= -google.golang.org/genproto/googleapis/api v0.0.0-20240521202816-d264139d666e/go.mod h1:LweJcLbyVij6rCex8YunD8DYR5VDonap/jYl3ZRxcIU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e h1:Elxv5MwEkCI9f5SkoL6afed6NTdxaGoAo39eANBwHL8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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= @@ -731,8 +731,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 9984cb6687862b954bc853d4fe180bddcfead27d Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Thu, 4 Jul 2024 18:43:56 +0200 Subject: [PATCH 19/28] updating to drand v2.0.1 --- go.mod | 32 ++++++++++--------- go.sum | 74 ++++++++++++++++++++++++++------------------ gossip-relay/main.go | 6 ++-- internal/cli.go | 13 ++++---- internal/lib/cli.go | 22 +++++++------ 5 files changed, 81 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index 0204591..07209fc 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22 require ( github.com/BurntSushi/toml v1.4.0 - github.com/drand/drand/v2 v2.0.6-testnet + github.com/drand/drand/v2 v2.0.1 github.com/drand/kyber v1.3.1 github.com/google/uuid v1.6.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 @@ -15,7 +15,7 @@ require ( github.com/jonboulle/clockwork v0.4.0 github.com/libp2p/go-libp2p v0.35.1 github.com/libp2p/go-libp2p-pubsub v0.11.0 - github.com/multiformats/go-multiaddr v0.12.4 + github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/nikkolasg/hexjson v0.1.0 github.com/pkg/errors v0.9.1 @@ -23,7 +23,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.2 golang.org/x/crypto v0.24.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 ) @@ -49,7 +49,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-chi/chi/v5 v5.0.13 // indirect + github.com/go-chi/chi/v5 v5.1.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect @@ -59,7 +59,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 // indirect + github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect @@ -101,36 +101,38 @@ require ( github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pion/datachannel v1.5.6 // indirect github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.25 // indirect + github.com/pion/ice/v2 v2.3.27 // indirect github.com/pion/interceptor v0.1.29 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.14 // indirect github.com/pion/rtp v1.8.6 // indirect - github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sctp v1.8.17 // indirect github.com/pion/sdp/v3 v3.0.9 // indirect github.com/pion/srtp/v2 v2.0.18 // indirect github.com/pion/stun v0.6.1 // indirect github.com/pion/transport/v2 v2.2.5 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.42 // indirect + github.com/pion/webrtc/v3 v3.2.44 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.54.0 // indirect + github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.45.0 // indirect + github.com/quic-go/quic-go v0.45.1 // indirect github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.10 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect @@ -142,19 +144,19 @@ require ( go.opentelemetry.io/otel/trace v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.22.0 // indirect + go.uber.org/fx v1.22.1 // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/mod v0.18.0 // indirect + golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.22.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index f86de90..4afadf4 100644 --- a/go.sum +++ b/go.sum @@ -28,6 +28,8 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -43,6 +45,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -81,8 +87,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/drand/drand/v2 v2.0.6-testnet h1:l/wx6as7LER+idrKTbENnuwB/DyFBcATNpXrEr0wwHY= -github.com/drand/drand/v2 v2.0.6-testnet/go.mod h1:4Dzpn1uQMlFs7vmoO3jGF3QL7WY6btmyeWi8ife/CJg= +github.com/drand/drand/v2 v2.0.1 h1:UGnzvBUAEOolNVGaz9UzZHdIhf55mjZbWg4kjotDbHk= +github.com/drand/drand/v2 v2.0.1/go.mod h1:SfzrKVexJwhwDral4tqS/E2bPTIEGC9P6H3DP/DXNmI= github.com/drand/kyber v1.3.1 h1:E0p6M3II+loMVwTlAp5zu4+GGZFNiRfq02qZxzw2T+Y= github.com/drand/kyber v1.3.1/go.mod h1:f+mNHjiGT++CuueBrpeMhFNdKZAsy0tu03bKq9D5LPA= github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= @@ -107,8 +113,8 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD 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/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-chi/chi/v5 v5.0.13 h1:JlH2F2M8qnwl0N1+JFFzlX9TlKJYas3aPXdiuTmJL+w= -github.com/go-chi/chi/v5 v5.0.13/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -157,8 +163,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M= -github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg= +github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 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.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -297,6 +303,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 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/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -308,8 +316,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= -github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= +github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -326,6 +334,8 @@ github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dy 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= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nikkolasg/hexjson v0.1.0 h1:Cgi1MSZVQFoJKYeRpBNEcdF3LB+Zo4fYKsDz7h8uJYQ= @@ -347,8 +357,8 @@ github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNI github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.25 h1:M5rJA07dqhi3nobJIg+uPtcVjFECTrhcR3n0ns8kDZs= -github.com/pion/ice/v2 v2.3.25/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/ice/v2 v2.3.27 h1:FF2O+hKUymskFTeyDvh+XwsNu5KBVhfihv6mtrMb8HQ= +github.com/pion/ice/v2 v2.3.27/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -364,8 +374,8 @@ github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= -github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= -github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sctp v1.8.17 h1:uK1VChU9C/J3Sj/Cq6cwEGtx2Gludgoi5zwZBZzWNT0= +github.com/pion/sctp v1.8.17/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= @@ -384,8 +394,8 @@ github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37 github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.42 h1:WN/ZuMjtpQOoGRCZUg/zFG+JHEvYLVyDKOxU6H1qWlE= -github.com/pion/webrtc/v3 v3.2.42/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= +github.com/pion/webrtc/v3 v3.2.44 h1:wL2X6xSVneYvNRWMdroHoiNAkF2rM6IIhV/oIz+iwJs= +github.com/pion/webrtc/v3 v3.2.44/go.mod h1:WRHWtbUNNtph0/FWtExX8cQl4EIpPrZec6gQf1tV6GE= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -399,15 +409,15 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 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/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE= -github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA= +github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -490,6 +500,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -515,8 +527,8 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.22.0 h1:pApUK7yL0OUHMd8vkunWSlLxZVFFk70jR2nKde8X2NM= -go.uber.org/fx v1.22.0/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= +go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys= +go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -569,8 +581,8 @@ golang.org/x/mod v0.3.0/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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= @@ -651,8 +663,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -717,10 +729,10 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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= @@ -729,8 +741,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -755,5 +767,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/gossip-relay/main.go b/gossip-relay/main.go index ddd7366..97de65e 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -80,15 +80,13 @@ var runCmd = &cli.Command{ Flags: append(lib.ClientFlags, []cli.Flag{ idFlag, peerWithFlag, - lib.HashListFlag, - lib.GroupConfListFlag, storeFlag, listenFlag, metricsFlag, }...), Action: func(cctx *cli.Context) error { - if cctx.IsSet(lib.HashFlag.Name) { - fmt.Printf("--%s is deprecated. Use --%s or --%s instead\n", lib.HashFlag.Name, lib.HashListFlag.Name, lib.GroupConfListFlag.Name) + if cctx.IsSet(lib.HashFlag.Name) || cctx.IsSet(lib.GroupConfFlag.Name) { + fmt.Printf("--%s and --%s are deprecated. Use --%s or --%s instead\n", lib.HashFlag.Name, lib.GroupConfFlag, lib.HashListFlag.Name, lib.GroupConfListFlag.Name) } switch { diff --git a/internal/cli.go b/internal/cli.go index 5ada1c2..7a57c52 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -60,17 +60,13 @@ var appCommands = []*cli.Command{ { Name: "get", Usage: "get allows for public information retrieval from a remote " + - "drand node.\n", + "drand http-relay.\n", Subcommands: []*cli.Command{ { Name: "public", Usage: "Get the latest public randomness from the drand " + - "beacon and verify it against the collective public key " + - "as specified in group.toml. Only one node is contacted by " + - "default. This command attempts to connect to the drand " + - "beacon via TLS and falls back to plaintext communication " + - "if the contacted node has not activated TLS in which case " + - "it prints a warning.\n", + "relay and verify it against the collective public key " + + "as specified in the chain-info.\n", Flags: toArray(roundFlag, relayFlag, jsonFlag), Action: getPublicRandomness, }, @@ -134,13 +130,16 @@ func toArray(flags ...cli.Flag) []cli.Flag { // TODO func getPublicRandomness(c *cli.Context) error { + fmt.Println("currently unimplemented") return nil } func getChainInfo(c *cli.Context) error { + fmt.Println("currently unimplemented") return nil } func schemesCmd(c *cli.Context) error { + fmt.Println("currently unimplemented") return nil } diff --git a/internal/lib/cli.go b/internal/lib/cli.go index a458aae..0b6c0d5 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -33,22 +33,21 @@ import ( var ( // URLFlag is the CLI flag for root URL(s) for fetching randomness. URLFlag = &cli.StringSliceFlag{ - Name: "url", - Usage: "root URL(s) for fetching randomness", - Aliases: []string{"http-relay-failover"}, // DEPRECATED + Name: "url", + Usage: "root URL(s) for fetching randomness", } // GRPCConnectFlag is the CLI flag for host:port to dial a gRPC randomness // provider. GRPCConnectFlag = &cli.StringFlag{ - Name: "grpc-connect", - Usage: "host:port to dial a gRPC randomness provider", - Aliases: []string{"connect"}, // DEPRECATED + Name: "grpc-connect", + Usage: "host:port to dial a gRPC randomness provider", } // HashFlag is the CLI flag for the hash (in hex) of the targeted chain. HashFlag = &cli.StringFlag{ Name: "hash", - Usage: "The hash (in hex) of the chain to follow", + Usage: "The hash (in hex) of the chain to follow. Deprecated and replaced by hash-list to support multiple chains", Aliases: []string{"chain-hash"}, + Hidden: true, } // HashListFlag is the CLI flag for the hashes list (in hex) for the relay to follow. HashListFlag = &cli.StringSliceFlag{ @@ -59,7 +58,8 @@ var ( GroupConfFlag = &cli.PathFlag{ Name: "group-conf", Usage: "Path to a drand group configuration (TOML encoded) or chain info (JSON encoded)," + - " can be used instead of `-hash` flag to verify the chain.", + " can be used instead of `-hash` flag to verify the chain. Deprecated and replaced by group-conf-list to support multiple chains", + Hidden: true, } // GroupConfListFlag is like GroupConfFlag but for a list values. GroupConfListFlag = &cli.StringSliceFlag{ @@ -97,6 +97,8 @@ var ClientFlags = []cli.Flag{ URLFlag, GRPCConnectFlag, HashFlag, + HashListFlag, + GroupConfListFlag, GroupConfFlag, InsecureFlag, RelayFlag, @@ -109,6 +111,7 @@ var ClientFlags = []cli.Flag{ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) (client.Client, error) { ctx := c.Context clients := make([]client.Client, 0) + l := log.DefaultLogger() var info *chainCommon.Info var err error @@ -116,6 +119,7 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) if groupPath := c.Path(GroupConfFlag.Name); groupPath != "" { info, err = chainInfoFromGroupTOML(groupPath) if err != nil { + l.Infow("Got a group conf file that is not a toml file. Trying it as a ChainInfo json file.", "path", groupPath) info, err = chainInfoFromChainInfoJSON(groupPath) if info == nil || err != nil { return nil, fmt.Errorf("failed to decode group (%s) : %w", groupPath, err) @@ -128,8 +132,6 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) hash = info.Hash() } - l := log.DefaultLogger() - grc, info, err := buildGrpcClient(c, info) if err != nil { return nil, err From d957ac2461d55069d186fed9dc000a1166d4d22f Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Fri, 5 Jul 2024 11:39:17 +0200 Subject: [PATCH 20/28] fix client --- gossip-relay/main.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gossip-relay/main.go b/gossip-relay/main.go index 97de65e..773e951 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -203,13 +203,24 @@ var clientCmd = &cli.Command{ Action: func(cctx *cli.Context) error { lg := log.New(nil, log.DefaultLevel, false) cctx.Context = log.ToContext(cctx.Context, lg) + if cctx.IsSet(lib.GroupConfListFlag.Name) { + groupConfs := cctx.StringSlice(lib.GroupConfListFlag.Name) + if len(groupConfs) != 1 { + return fmt.Errorf("please specify a single valid chain using the --%s flag with the client command") + } + + if cctx.IsSet(lib.GroupConfFlag.Name) { + return fmt.Errorf("please do not use both --%s and --%s at the same time", lib.GroupConfFlag.Name, lib.GroupConfListFlag.Name) + } + cctx.Set(lib.GroupConfFlag.Name, groupConfs[0]) + } c, err := lib.Create(cctx, false) if err != nil { return fmt.Errorf("constructing client: %w", err) } for rand := range c.Watch(cctx.Context) { - lg.Infow("", "client", "got randomness", "round", rand.GetRound(), "signature", rand.GetSignature()[:16]) + lg.Infow("", "client", "got randomness", "round", rand.GetRound(), "signature", hex.EncodeToString(rand.GetSignature())) } return nil From 95998f3b04add8fb4d71197038f129d2255a9c19 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Fri, 12 Jul 2024 15:35:21 +0200 Subject: [PATCH 21/28] train work --- .golangci.yml | 195 ++++ Makefile | 2 + client/empty_test.go | 3 +- client/http/http.go | 9 +- client/http/http_test.go | 3 +- client/http/metric.go | 15 +- client/lp2p/client.go | 11 +- client/lp2p/client_test.go | 9 +- client/lp2p/validator.go | 3 +- client/test/http/mock/httpserver.go | 15 +- client/test/result/mock/result.go | 4 +- go.mod | 1 + gossip-relay/main.go | 2 +- internal/cli.go | 92 +- internal/cli_test.go | 1526 +-------------------------- internal/grpc/client_test.go | 6 +- internal/lib/cli.go | 7 +- internal/lib/cli_test.go | 12 +- internal/lp2p/ctor_test.go | 3 +- internal/lp2p/relaynode_test.go | 3 +- internal/metrics/metrics.go | 462 ++++++++ internal/metrics/metrics_test.go | 23 + internal/metrics/pprof/pprof.go | 23 + 23 files changed, 841 insertions(+), 1588 deletions(-) create mode 100644 .golangci.yml create mode 100644 Makefile create mode 100644 internal/metrics/metrics.go create mode 100644 internal/metrics/metrics_test.go create mode 100644 internal/metrics/pprof/pprof.go diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..60fa1d0 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,195 @@ +issues: + # Let us display all issues of one type at once + max-same-issues: 0 + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - path: _test\.go + linters: + - bodyclose + - cyclop + - errcheck + - forbidigo + - goconst + - gocyclo + - mnd + - gosec + - nilnil + - noctx + - revive + - depguard + - lll # signatures are long lines + - path: _test\.go + text: "SA1019" # we still want to test deprecated functions + - path: cmd + linters: + - forbidigo # we use Println in our UX + - path: internal/lib + linters: + - forbidigo # we use Println in our UX + - path: internal/drand-cli + linters: + - forbidigo # we use Println in our UX + - goconst # we re-use some strings in our flags +run: + skip-dirs: + - demo + +linters: + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + #- containedctx #TODO could be enabled + #- contextcheck #TODO could be enabled + #- cyclop + #- deadcode # Deprecated + - decorder + # - depguard + - dogsled + - dupl + - dupword + - durationcheck + - errcheck + - errchkjson + - errname + - errorlint + # - execinquery # deprecated + - exhaustive + # - exhaustivestruct + # - exhaustruct + - exportloopref + - forbidigo + # - forcetypeassert #TODO could be enabled + - funlen + # - gci + # - gochecknoglobals + - gochecknoinits + # - gocognit + - goconst + - gocritic + - gocyclo + # - godot + # - godox #TODO could be enabled + # - goerr113 + - gofmt + # - gofumpt + - goheader + - goimports + # - golint # Deprecated + # - gomnd # deprecated, replaced by mnd + # - gomoddirectives + - gomodguard + - goprintffuncname + - gosec + - gosimple + - govet + - grouper + # - ifshort + - importas + - ineffassign + - interfacebloat + # - interfacer # Deprecated + # - ireturn + - lll + - loggercheck + - maintidx + - makezero + # - maligned #Deprecated + - mnd + - misspell + - nakedret + # - nestif + - nilerr + - nilnil + # - nlreturn + - noctx + - nolintlint + # - nonamedreturns + # - nosnakecase + - nosprintfhostport + # - paralleltest #TODO could be enabled + - prealloc + - predeclared + # - promlinter #TODO could be enabled + - reassign + - revive + - rowserrcheck + # - scopelint # Deprecated + - sqlclosecheck + - staticcheck + # - structcheck # Deprecated + - stylecheck + # - tagliatelle + - tenv + - testableexamples + # - testpackage + # - thelper #TODO could be enabled + - tparallel + - typecheck + - unconvert + - unparam + - unused + - usestdlibvars + # - varcheck # Deprecated + # - varnamelen + - wastedassign + - whitespace + # - wrapcheck + # - wsl + +linters-settings: + dupl: + threshold: 100 + exhaustive: + default-signifies-exhaustive: false + funlen: + lines: 100 + statements: 50 + goconst: + min-len: 3 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - ifElseChain + - octalLiteral + - whyNoLint + - wrapperFunc + gocyclo: + min-complexity: 15 + goimports: + local-prefixes: github.com/drand + golint: + min-confidence: 0 + mnd: + # don't include the "operation" and "assign" + checks: + - argument + - case + - condition + - return + lll: + line-length: 140 +# maligned: # Deprecated +# suggest-new: true +# govet: +# check-shadowing: true #TODO could be enabled +# enable: +# - fieldalignment #TODO could be enabled + revive: + enable: + - var-naming + misspell: + locale: US + nolintlint: + allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7de4890 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +drand-relay-gossip: + go build -o drand-relay-gossip ./gossip-relay/main.go diff --git a/client/empty_test.go b/client/empty_test.go index fc2929e..8b672a8 100644 --- a/client/empty_test.go +++ b/client/empty_test.go @@ -3,10 +3,11 @@ package client import ( "context" "fmt" - commonutils "github.com/drand/drand/v2/common" "testing" "time" + commonutils "github.com/drand/drand/v2/common" + chain2 "github.com/drand/drand/v2/common/client" ) diff --git a/client/http/http.go b/client/http/http.go index ce86831..1f0403d 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -13,11 +13,12 @@ import ( client2 "github.com/drand/drand-cli/client" + json "github.com/nikkolasg/hexjson" + "github.com/drand/drand/v2/common" chain2 "github.com/drand/drand/v2/common/chain" "github.com/drand/drand/v2/common/client" "github.com/drand/drand/v2/common/log" - json "github.com/nikkolasg/hexjson" ) var errClientClosed = fmt.Errorf("client closed") @@ -44,7 +45,7 @@ func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transp agent := fmt.Sprintf("drand-client-%s/1.0", path.Base(pn)) c := &httpClient{ root: url, - client: createClient(url, transport), + client: createClient(transport), l: l, Agent: agent, done: make(chan struct{}), @@ -76,7 +77,7 @@ func NewWithInfo(l log.Logger, url string, info *chain2.Info, transport nhttp.Ro c := &httpClient{ root: url, chainInfo: info, - client: createClient(url, transport), + client: createClient(transport), l: l, Agent: agent, done: make(chan struct{}), @@ -137,7 +138,7 @@ func Ping(ctx context.Context, root string) error { } // createClient creates an HTTP client around a transport, allows to easily instrument it later -func createClient(url string, transport nhttp.RoundTripper) *nhttp.Client { +func createClient(transport nhttp.RoundTripper) *nhttp.Client { hc := nhttp.Client{} hc.Timeout = defaultHTTTPTimeout hc.Jar = nhttp.DefaultClient.Jar diff --git a/client/http/http_test.go b/client/http/http_test.go index f3eef99..b38e7a0 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -8,10 +8,11 @@ import ( "testing" "time" - "github.com/drand/drand/v2/common/log" clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/test/http/mock" "github.com/drand/drand/v2/crypto" diff --git a/client/http/metric.go b/client/http/metric.go index c46564d..63cadaf 100644 --- a/client/http/metric.go +++ b/client/http/metric.go @@ -2,9 +2,11 @@ package http import ( "context" - "fmt" "time" + "github.com/prometheus/client_golang/prometheus" + + "github.com/drand/drand-cli/internal/metrics" "github.com/drand/drand/v2/common" chain2 "github.com/drand/drand/v2/common/client" @@ -31,7 +33,6 @@ type HealthMetrics struct { // HeartbeatInterval is the duration between liveness heartbeats sent to an HTTP API. const HeartbeatInterval = 10 * time.Second -// TODO add metrics back in func (c *HealthMetrics) startObserve(ctx context.Context) { // we check all clients within HeartbeatInterval interval := time.Duration(int64(HeartbeatInterval) / int64(len(c.clients))) @@ -51,19 +52,19 @@ func (c *HealthMetrics) startObserve(ctx context.Context) { result, err := c.clients[n].Get(ctx, c.clients[n].RoundAt(time.Now())+1) if err != nil { - //metrics.ClientHTTPHeartbeatFailure.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + metrics.ClientHTTPHeartbeatFailure.With(prometheus.Labels{"http_address": httpClient.root}).Inc() continue } - //metrics.ClientHTTPHeartbeatSuccess.With(prometheus.Labels{"http_address": httpClient.root}).Inc() + metrics.ClientHTTPHeartbeatSuccess.With(prometheus.Labels{"http_address": httpClient.root}).Inc() // compute the latency metric actual := time.Now().UnixNano() expected := common.TimeOfRound(httpClient.chainInfo.Period, httpClient.chainInfo.GenesisTime, result.GetRound()) * 1e9 // the labels of the gauge vec must already be set at the registerer level - //metrics.ClientHTTPHeartbeatLatency.With(prometheus.Labels{"http_address": httpClient.root}). - // Set(float64(actual-expected) / float64(time.Millisecond)) - fmt.Println(float64(actual-expected) / float64(time.Millisecond)) + metrics.ClientHTTPHeartbeatLatency. + With(prometheus.Labels{"http_address": httpClient.root}). + Set(float64(actual-expected) / float64(time.Millisecond)) c.next++ } } diff --git a/client/lp2p/client.go b/client/lp2p/client.go index 9407ca0..a9ac833 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -17,6 +17,7 @@ import ( "github.com/drand/drand/v2/common/chain" "github.com/drand/drand/v2/common/client" "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" "github.com/drand/drand/v2/protobuf/drand" ) @@ -199,13 +200,13 @@ func (c *Client) Watch(ctx context.Context) <-chan client.Result { return } dat := &client2.RandomData{ - Rnd: resp.Round, - Random: resp.Randomness, - Sig: resp.Signature, - PreviousSignature: resp.PreviousSignature, + Rnd: resp.GetRound(), + Random: crypto.RandomnessFromSignature(resp.GetSignature()), + Sig: resp.GetSignature(), + PreviousSignature: resp.GetPreviousSignature(), } if c.cache != nil { - c.cache.Add(resp.Round, dat) + c.cache.Add(resp.GetRound(), dat) } select { case outerCh <- dat: diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index 6df3324..d055da1 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -5,14 +5,15 @@ import ( "testing" "time" - "github.com/drand/drand/v2/common/client" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" + + "github.com/drand/drand/v2/common/client" ) // -//func TestGRPCClientTestFunc(t *testing.T) { +// func TestGRPCClientTestFunc(t *testing.T) { // lg := log.New(nil, log.DebugLevel, true) // // start mock drand node // sch, err := crypto.GetSchemeFromEnv() @@ -105,7 +106,7 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { } // -//func TestHTTPClientTestFunc(t *testing.T) { +// func TestHTTPClientTestFunc(t *testing.T) { // if testing.Short() { // t.Skip("skipping slow test in short mode.") // } @@ -169,7 +170,7 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { // drain(t, ch, 5*time.Second) //} -//func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { +// func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { // dataDir := t.TempDir() // identityDir := t.TempDir() // ds, err := bds.NewDatastore(dataDir, nil) diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go index 67eeec8..e0ce892 100644 --- a/client/lp2p/validator.go +++ b/client/lp2p/validator.go @@ -3,9 +3,10 @@ package lp2p import ( "bytes" "context" + "time" + "github.com/drand/drand-cli/client" commonutils "github.com/drand/drand/v2/common" - "time" clock "github.com/jonboulle/clockwork" pubsub "github.com/libp2p/go-libp2p-pubsub" diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index 2896733..ce8b124 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -7,6 +7,10 @@ import ( "testing" "time" + clock "github.com/jonboulle/clockwork" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" + localClient "github.com/drand/drand-cli/client" "github.com/drand/drand/v2/common" "github.com/drand/drand/v2/common/chain" @@ -14,9 +18,6 @@ import ( dhttp "github.com/drand/drand/v2/handler/http" "github.com/drand/drand/v2/protobuf/drand" "github.com/drand/drand/v2/test/mock" - clock "github.com/jonboulle/clockwork" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/peer" "github.com/drand/drand/v2/crypto" ) @@ -92,10 +93,10 @@ func (d *drandProxy) Get(ctx context.Context, round uint64) (client.Result, erro return nil, err } return &localClient.RandomData{ - Rnd: resp.Round, - Random: resp.Randomness, - Sig: resp.Signature, - PreviousSignature: resp.PreviousSignature, + Rnd: resp.GetRound(), + Random: crypto.RandomnessFromSignature(resp.GetSignature()), + Sig: resp.GetSignature(), + PreviousSignature: resp.GetPreviousSignature(), }, nil } diff --git a/client/test/result/mock/result.go b/client/test/result/mock/result.go index ba15978..7eec852 100644 --- a/client/test/result/mock/result.go +++ b/client/test/result/mock/result.go @@ -99,7 +99,7 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { var msg []byte if sch.Name == crypto.DefaultSchemeID { // we're in chained mode - msg = sha256Hash(previous[:], i+1) + msg = sha256Hash(previous, i+1) } else { // we are in unchained mode msg = sha256Hash(nil, i+1) @@ -123,7 +123,7 @@ func VerifiableResults(count int, sch *crypto.Scheme) (*chain.Info, []Result) { // chained mode if sch.Name == crypto.DefaultSchemeID { previous = make([]byte, len(sig)) - copy(previous[:], sig) + copy(previous, sig) } else { previous = nil } diff --git a/go.mod b/go.mod index 07209fc..ebf23ee 100644 --- a/go.mod +++ b/go.mod @@ -131,6 +131,7 @@ require ( github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.10 // indirect diff --git a/gossip-relay/main.go b/gossip-relay/main.go index 773e951..f3dd64d 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -206,7 +206,7 @@ var clientCmd = &cli.Command{ if cctx.IsSet(lib.GroupConfListFlag.Name) { groupConfs := cctx.StringSlice(lib.GroupConfListFlag.Name) if len(groupConfs) != 1 { - return fmt.Errorf("please specify a single valid chain using the --%s flag with the client command") + return fmt.Errorf("please specify a single valid chain using the --%s flag with the client command", lib.GroupConfListFlag.Name) } if cctx.IsSet(lib.GroupConfFlag.Name) { diff --git a/internal/cli.go b/internal/cli.go index 7a57c52..5a61345 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -2,10 +2,15 @@ package drand import ( "fmt" + "log" + "os" "sync" "github.com/urfave/cli/v2" + client "github.com/drand/drand/v2/common/client" + + "github.com/drand/drand-cli/internal/lib" "github.com/drand/drand/v2/common" ) @@ -24,38 +29,6 @@ var verboseFlag = &cli.BoolFlag{ EnvVars: []string{"DRAND_VERBOSE"}, } -var relayFlag = &cli.StringSliceFlag{ - Name: "relays", - Usage: "Contact the HTTP relay at the given URL address. Can be specified multiple times to try multiple relays.", - EnvVars: []string{"DRAND_HTTP_RELAY"}, -} - -var roundFlag = &cli.IntFlag{ - Name: "round", - Usage: "Request the public randomness generated at round num. If the requested value doesn't exist yet," + - " it returns an error. If not specified or 0, the latest beacon is returned.", - EnvVars: []string{"DRAND_ROUND"}, -} - -var hashInfoFlag = &cli.StringFlag{ - Name: "chain-hash", - Usage: "The hash of the chain info", - EnvVars: []string{"DRAND_CHAIN_HASH"}, -} - -var jsonFlag = &cli.BoolFlag{ - Name: "json", - Usage: "Set the output as json format", - EnvVars: []string{"DRAND_JSON"}, -} - -var beaconIDFlag = &cli.StringFlag{ - Name: "id", - Usage: "Indicates the id of the beacon chain you're interested in", - Value: "", - EnvVars: []string{"DRAND_ID"}, -} - var appCommands = []*cli.Command{ { Name: "get", @@ -67,14 +40,15 @@ var appCommands = []*cli.Command{ Usage: "Get the latest public randomness from the drand " + "relay and verify it against the collective public key " + "as specified in the chain-info.\n", - Flags: toArray(roundFlag, relayFlag, jsonFlag), - Action: getPublicRandomness, + Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag), + ArgsUsage: "--url url1 --url url2 ROUND... uses the first working relay to query round number ROUND", + Action: getPublicRandomness, }, { Name: "chain-info", - Usage: "Get the binding chain information that this node participates to", - ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.", - Flags: toArray(hashInfoFlag, relayFlag, jsonFlag), + Usage: "Get beacon information", + ArgsUsage: "--url url1 --url url2 ... uses the first working relay", + Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag), Action: getChainInfo, }, }, @@ -128,18 +102,46 @@ func toArray(flags ...cli.Flag) []cli.Flag { return flags } -// TODO -func getPublicRandomness(c *cli.Context) error { - fmt.Println("currently unimplemented") - return nil +func instantiateClient(cctx *cli.Context) (client.Client, error) { + c, err := lib.Create(cctx, false) + if err != nil { + return nil, fmt.Errorf("constructing client: %w", err) + } + + _, err = c.Info(cctx.Context) + if err != nil { + return nil, fmt.Errorf("cannot retrieve chain info from relay: %w", err) + } + + return c, nil } -func getChainInfo(c *cli.Context) error { - fmt.Println("currently unimplemented") +func getPublicRandomness(cctx *cli.Context) error { + c, err := instantiateClient(cctx) + if err != nil { + return err + } + if len(os.Args) > 1 { + log.Fatal("please specify a single round as positional argument") + } + + round, err := c.Get(cctx.Context, 0) + if err != nil { + return err + } + fmt.Println(round) return nil } -func schemesCmd(c *cli.Context) error { - fmt.Println("currently unimplemented") +func getChainInfo(cctx *cli.Context) error { + c, err := instantiateClient(cctx) + if err != nil { + return err + } + info, err := c.Info(cctx.Context) + if err != nil { + return err + } + fmt.Println(info) return nil } diff --git a/internal/cli_test.go b/internal/cli_test.go index 47f6109..2315ea5 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -1,1494 +1,36 @@ package drand -//import ( -// "bytes" -// "context" -// "encoding/hex" -// "errors" -// "fmt" -// gnet "net" -// "os" -// "os/exec" -// "path" -// "path/filepath" -// "strconv" -// "strings" -// "testing" -// "time" -// -// "github.com/BurntSushi/toml" -// "github.com/kabukky/httpscerts" -// json "github.com/nikkolasg/hexjson" -// "github.com/stretchr/testify/require" -// -// "github.com/drand/drand-cli/internal/chain" -// "github.com/drand/drand-cli/internal/chain/boltdb" -// "github.com/drand/drand-cli/internal/core" -// dkg2 "github.com/drand/drand-cli/internal/dkg" -// "github.com/drand/drand-cli/internal/fs" -// "github.com/drand/drand-cli/internal/net" -// "github.com/drand/drand-cli/internal/test" -// "github.com/drand/drand/v2/common" -// chain2 "github.com/drand/drand/v2/common/chain" -// "github.com/drand/drand/v2/common/key" -// "github.com/drand/drand/v2/common/log" -// "github.com/drand/drand/v2/crypto" -// "github.com/drand/kyber" -// "github.com/drand/kyber/share" -// "github.com/drand/kyber/share/dkg" -// "github.com/drand/kyber/util/random" -//) -// -// -//func TestResetError(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := getSBFolderStructure(t) -// -// args := []string{"drand", "util", "reset", "--folder", tmp, "--id", beaconID} -// app := CLI() -// require.Error(t, app.Run(args)) -//} -// -//func TestDeleteBeaconError(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := getSBFolderStructure(t) -// -// // that command should delete round 3 and 4 -// args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} -// app := CLI() -// require.Error(t, app.Run(args)) -//} -// -//func TestDeleteBeacon(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// l := log.New(nil, log.DebugLevel, true) -// ctx := context.Background() -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// if sch.Name == crypto.DefaultSchemeID { -// ctx = chain.SetPreviousRequiredOnContext(ctx) -// } -// tmp := path.Join(t.TempDir(), "drand") -// -// opt := core.WithConfigFolder(tmp) -// conf := core.NewConfig(l, opt) -// fs.CreateSecureFolder(conf.DBFolder(beaconID)) -// store, err := boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) -// require.NoError(t, err) -// err = store.Put(ctx, &common.Beacon{ -// Round: 1, -// Signature: []byte("Hello"), -// }) -// require.NoError(t, err) -// err = store.Put(ctx, &common.Beacon{ -// Round: 2, -// Signature: []byte("Hello"), -// }) -// require.NoError(t, err) -// err = store.Put(ctx, &common.Beacon{ -// Round: 3, -// Signature: []byte("Hello"), -// }) -// require.NoError(t, err) -// err = store.Put(ctx, &common.Beacon{ -// Round: 4, -// Signature: []byte("hello"), -// }) -// require.NoError(t, err) -// // try to fetch round 3 and 4 -// b, err := store.Get(ctx, 3) -// require.NoError(t, err) -// require.NotNil(t, b) -// b, err = store.Get(ctx, 4) -// require.NoError(t, err) -// require.NotNil(t, b) -// -// err = store.Close() -// require.NoError(t, err) -// -// args := []string{"drand", "util", "del-beacon", "--folder", tmp, "--id", beaconID, "3"} -// app := CLI() -// require.NoError(t, app.Run(args)) -// -// store, err = boltdb.NewBoltStore(ctx, l, conf.DBFolder(beaconID), conf.BoltOptions()) -// require.NoError(t, err) -// -// // try to fetch round 3 and 4 - it should now fail -// _, err = store.Get(ctx, 3) -// require.Error(t, err) -// -// _, err = store.Get(ctx, 4) -// require.Error(t, err) -//} -// -//func TestKeySelfSignError(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := getSBFolderStructure(t) -// -// args := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} -// app := CLI() -// require.Error(t, app.Run(args)) -//} -// -//func TestKeySelfSign(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// l := log.New(nil, log.DebugLevel, true) -// -// tmp := path.Join(t.TempDir(), "drand") -// -// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} -// require.NoError(t, CLI().Run(args)) -// -// selfSign := []string{"drand", "util", "self-sign", "--folder", tmp, "--id", beaconID} -// // try self sign, it should only print that it's already the case -// expectedOutput := "already self signed" -// testCommand(t, selfSign, expectedOutput) -// -// // load, remove signature and save -// config := core.NewConfig(l, core.WithConfigFolder(tmp)) -// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) -// -// pair, err := fileStore.LoadKeyPair(nil) -// require.NoError(t, err) -// pair.Public.Signature = nil -// require.NoError(t, fileStore.SaveKeyPair(pair)) -// -// expectedOutput = "identity self signed" -// testCommand(t, selfSign, expectedOutput) -//} -// -//func TestKeyGenError(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := getSBFolderStructure(t) -// -// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1:8081"} -// app := CLI() -// require.Error(t, app.Run(args)) -//} -// -//func TestKeyGen(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// l := log.New(nil, log.DebugLevel, true) -// -// tmp := path.Join(t.TempDir(), "drand") -// sch, _ := crypto.GetSchemeFromEnv() -// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "--scheme", sch.Name, "127.0.0.1:8081"} -// require.NoError(t, CLI().Run(args)) -// -// config := core.NewConfig(l, core.WithConfigFolder(tmp)) -// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) -// priv, err := fileStore.LoadKeyPair(nil) -// require.NoError(t, err) -// require.NotNil(t, priv.Public) -// -// tmp2 := path.Join(t.TempDir(), "drand2") -// -// args = []string{"drand", "generate-keypair", "--folder", tmp2, "--id", beaconID, "--scheme", sch.Name} -// require.Error(t, CLI().Run(args)) -// -// config = core.NewConfig(l, core.WithConfigFolder(tmp2)) -// fileStore = key.NewFileStore(config.ConfigFolderMB(), beaconID) -// priv, err = fileStore.LoadKeyPair(nil) -// require.Error(t, err) -// require.Nil(t, priv) -//} -// -//// tests valid commands and then invalid commands -//func TestStartAndStop(t *testing.T) { -// tmpPath := t.TempDir() -// -// n := 5 -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// _, group := test.BatchIdentities(n, sch, beaconID) -// groupPath := path.Join(tmpPath, "group.toml") -// require.NoError(t, key.Save(groupPath, group, false)) -// -// privateAddr := test.Addresses(1)[0] -// -// args := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmpPath, "--id", beaconID, privateAddr} -// require.NoError(t, CLI().Run(args)) -// -// startCh := make(chan bool) -// go func() { -// startArgs := []string{"drand", "start", "--tls-disable", "--folder", tmpPath, "--private-listen", privateAddr} -// // Allow the rest of the test to start -// // Any error will be caught in the error check below -// startCh <- true -// err := CLI().Run(startArgs) -// if err != nil { -// t.Errorf("error starting the node %s\n", err) -// t.Fail() -// return -// } -// // After we finish the execution, flag that we finished. -// // This allows the test to exit cleanly without reaching the -// // timeout at the end. -// startCh <- true -// // TODO : figuring out how to not panic in grpc call -// // ERROR: 2020/01/23 21:06:28 grpc: server failed to encode response: -// // rpc error: code = Internal desc = grpc: error while marshaling: proto: -// // Marshal called with nil -// }() -// <-startCh -// time.Sleep(200 * time.Millisecond) -// -// stopArgs := []string{"drand", "stop"} -// err = CLI().Run(stopArgs) -// require.NoError(t, err) -// -// select { -// case <-startCh: -// case <-time.After(1 * time.Second): -// t.Fatal("drand daemon did not stop") -// } -//} -// -//func TestUtilCheckReturnsErrorForPortNotMatchingKeypair(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := t.TempDir() -// -// // try to generate a keypair and make it listen on another address -// keyPort := test.FreePort() -// keyAddr := "127.0.0.1:" + keyPort -// generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} -// require.NoError(t, CLI().Run(generate)) -// -// listenPort := test.FreePort() -// listenAddr := "127.0.0.1:" + listenPort -// listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", listenAddr, "--folder", tmp} -// ctx, cancel := context.WithCancel(context.Background()) -// defer cancel() -// -// waitCh := make(chan bool) -// go func() { -// waitCh <- true -// err := CLI().RunContext(ctx, listen) -// if err != nil { -// t.Errorf("error while starting the node %v\n", err) -// t.Fail() -// return -// } -// }() -// <-waitCh -// // TODO can we maybe try to bind continuously to not having to wait -// time.Sleep(200 * time.Millisecond) -// -// // run the check tool it should fail because key and address are not -// // consistent -// check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, listenAddr} -// require.Error(t, CLI().Run(check)) -//} -// -//func TestUtilCheckSucceedsForPortMatchingKeypair(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := t.TempDir() -// -// keyPort := test.FreePort() -// keyAddr := "127.0.0.1:" + keyPort -// generate := []string{"drand", "generate-keypair", "--tls-disable", "--folder", tmp, "--id", beaconID, keyAddr} -// require.NoError(t, CLI().Run(generate)) -// -// listen := []string{"drand", "start", "--tls-disable", "--control", test.FreePort(), "--private-listen", keyAddr, "--folder", tmp} -// ctx, cancel := context.WithCancel(context.Background()) -// defer cancel() -// -// waitCh := make(chan bool) -// go func() { -// waitCh <- true -// err := CLI().RunContext(ctx, listen) -// if err != nil { -// t.Errorf("error while starting the node %v\n", err) -// t.Fail() -// return -// } -// }() -// <-waitCh -// // TODO can we maybe try to bind continuously to not having to wait -// time.Sleep(200 * time.Millisecond) -// -// check := []string{"drand", "util", "check", "--tls-disable", "--id", beaconID, keyAddr} -// require.NoError(t, CLI().Run(check)) -//} -// -////nolint:funlen -//func TestStartWithoutGroup(t *testing.T) { -// lg := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// tmpPath := path.Join(t.TempDir(), "drand") -// require.NoError(t, os.Mkdir(tmpPath, 0o740)) -// -// pubPath := path.Join(tmpPath, "pub.key") -// port1, _ := strconv.Atoi(test.FreePort()) -// addr := "127.0.0.1:" + strconv.Itoa(port1) -// -// ctrlPort1, ctrlPort2, metricsPort := test.FreePort(), test.FreePort(), test.FreePort() -// -// priv, err := key.NewKeyPair(addr, sch) -// require.NoError(t, err) -// require.NoError(t, key.Save(pubPath, priv.Public, false)) -// -// config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) -// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) -// require.NoError(t, fileStore.SaveKeyPair(priv)) -// -// startArgs := []string{ -// "drand", -// "start", -// "--private-listen", priv.Public.Address(), -// "--tls-disable", -// "--verbose", -// "--folder", tmpPath, -// "--control", ctrlPort1, -// "--metrics", "127.0.0.1:" + metricsPort, -// } -// -// go func() { -// err := CLI().Run(startArgs) -// if err != nil { -// t.Errorf(err.Error()) -// } -// }() -// -// time.Sleep(500 * time.Millisecond) -// -// t.Log("--- DRAND SHARE --- (expected to fail)") -// // this must fail because not enough arguments -// // TODO - test vectors testing on the inputs -// -// initDKGArgs := []string{"drand", "share", "--control", ctrlPort1, "--id", beaconID} -// require.Error(t, CLI().Run(initDKGArgs)) -// -// t.Log("--- DRAND STOP --- (failing instance)") -// err = CLI().Run([]string{"drand", "stop", "--control", ctrlPort1}) -// require.NoError(t, err) -// -// t.Log(" --- DRAND GROUP ---") -// -// // fake group -// _, group := test.BatchIdentities(5, sch, beaconID) -// -// // fake dkg output -// fakeKey := sch.KeyGroup.Point().Pick(random.New()) -// distKey := &key.DistPublic{ -// Coefficients: []kyber.Point{ -// fakeKey, -// sch.KeyGroup.Point().Pick(random.New()), -// sch.KeyGroup.Point().Pick(random.New()), -// }, -// } -// priv.Public.TLS = false -// -// group.Period = 5 * time.Second -// group.GenesisTime = time.Now().Unix() - 10 -// group.PublicKey = distKey -// group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} -// group.Nodes[1] = &key.Node{Identity: priv.Public, Index: 1} -// groupPath := path.Join(tmpPath, "drand_group.toml") -// require.NoError(t, key.Save(groupPath, group, false)) -// -// // save it also to somewhere drand will find it -// require.NoError(t, fileStore.SaveGroup(group)) -// -// // fake share -// scalarOne := sch.KeyGroup.Scalar().One() -// s := &share.PriShare{I: 2, V: scalarOne} -// fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} -// require.NoError(t, fileStore.SaveShare(fakeShare)) -// -// // save a fake complete DKG in the store -// dStore, err := dkg2.NewDKGStore(tmpPath, nil) -// require.NoError(t, err) -// err = dStore.SaveFinished(beaconID, &dkg2.DBState{ -// BeaconID: beaconID, -// Epoch: 1, -// State: dkg2.Complete, -// Threshold: 1, -// Timeout: time.Unix(2549084715, 0).UTC(), // this will need updated in 2050 :^) -// SchemeID: sch.Name, -// GenesisTime: time.Unix(1669718523, 0).UTC(), -// GenesisSeed: []byte("deadbeef"), -// TransitionTime: time.Unix(1669718523, 0).UTC(), -// CatchupPeriod: 5 * time.Second, -// BeaconPeriod: 10 * time.Second, -// -// Leader: nil, -// Remaining: nil, -// Joining: nil, -// Leaving: nil, -// -// Acceptors: nil, -// Rejectors: nil, -// -// FinalGroup: group, -// KeyShare: fakeShare, -// }) -// require.NoError(t, err) -// -// // Have to close it afterwards or starting the node will become unresponsive -// err = dStore.Close() -// require.NoError(t, err) -// -// t.Logf(" --- DRAND START --- control %s\n", ctrlPort2) -// -// start2 := []string{ -// "drand", -// "start", -// "--control", ctrlPort2, -// "--private-listen", priv.Public.Address(), -// "--tls-disable", -// "--folder", tmpPath, -// "--verbose", -// } -// -// go func() { -// err := CLI().Run(start2) -// if err != nil { -// t.Errorf("error while starting second node: %v", err) -// } -// }() -// -// stop2 := []string{"drand", "stop", "--control", ctrlPort2} -// defer func() { -// err := CLI().Run(stop2) -// if err != nil { -// t.Errorf("error while stopping second node: %v", err) -// } -// }() -// -// time.Sleep(500 * time.Millisecond) -// -// testStartedDrandFunctional(t, ctrlPort2, tmpPath, priv.Public.Address(), group, fileStore, beaconID) -//} -// -//func testStartedDrandFunctional(t *testing.T, ctrlPort, rootPath, address string, group *key.Group, fileStore key.Store, beaconID string) { -// t.Helper() -// lg := log.New(nil, log.DebugLevel, true) -// -// testPing(t, ctrlPort) -// testStatus(t, ctrlPort, beaconID) -// testListSchemes(t, ctrlPort) -// -// require.NoError(t, toml.NewEncoder(os.Stdout).Encode(group.TOML())) -// -// t.Log("Running CHAIN-INFO command") -// chainInfo, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") -// require.NoError(t, err) -// expectedOutput := string(chainInfo) -// chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-disable", address} -// testCommand(t, chainInfoCmd, expectedOutput) -// -// t.Log("Running CHAIN-INFO --HASH command") -// chainInfoCmdHash := []string{"drand", "get", "chain-info", "--hash", "--tls-disable", address} -// expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) -// testCommand(t, chainInfoCmdHash, expectedOutput) -// -// showChainInfo := []string{"drand", "show", "chain-info", "--control", ctrlPort} -// buffCi, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") -// require.NoError(t, err) -// testCommand(t, showChainInfo, string(buffCi)) -// -// showChainInfo = []string{"drand", "show", "chain-info", "--hash", "--control", ctrlPort} -// expectedOutput = fmt.Sprintf("%x", chain2.NewChainInfo(lg, group).Hash()) -// testCommand(t, showChainInfo, expectedOutput) -// -// // reset state -// resetCmd := []string{"drand", "util", "reset", "--folder", rootPath, "--id", beaconID} -// r, w, err := os.Pipe() -// require.NoError(t, err) -// _, err = w.WriteString("y\n") -// require.NoError(t, err) -// os.Stdin = r -// require.NoError(t, CLI().Run(resetCmd)) -// _, err = fileStore.LoadShare(nil) -// require.Error(t, err) -// _, err = fileStore.LoadGroup() -// require.Error(t, err) -//} -// -//func testPing(t *testing.T, ctrlPort string) { -// t.Helper() -// -// var err error -// -// t.Logf(" + running PING command with %s\n", ctrlPort) -// for i := 0; i < 3; i++ { -// ping := []string{"drand", "util", "ping", "--control", ctrlPort} -// err = CLI().Run(ping) -// if err == nil { -// break -// } -// time.Sleep(500 * time.Millisecond) -// } -// require.NoError(t, err) -//} -// -//func testStatus(t *testing.T, ctrlPort, beaconID string) { -// t.Helper() -// -// var err error -// -// t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) -// for i := 0; i < 3; i++ { -// status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} -// err = CLI().Run(status) -// if err == nil { -// return -// } -// time.Sleep(500 * time.Millisecond) -// } -// require.NoError(t, err) -//} -// -//func testFailStatus(t *testing.T, ctrlPort, beaconID string) { -// t.Helper() -// -// var err error -// -// t.Logf(" + running STATUS command with %s on beacon [%s]\n", ctrlPort, beaconID) -// for i := 0; i < 3; i++ { -// status := []string{"drand", "util", "status", "--control", ctrlPort, "--id", beaconID} -// err = CLI().Run(status) -// require.Error(t, err) -// time.Sleep(500 * time.Millisecond) -// } -//} -// -//func testListSchemes(t *testing.T, ctrlPort string) { -// t.Helper() -// -// var err error -// -// t.Logf(" + running list schemes command with %s\n", ctrlPort) -// for i := 0; i < 3; i++ { -// schemes := []string{"drand", "util", "list-schemes", "--control", ctrlPort} -// err = CLI().Run(schemes) -// if err == nil { -// break -// } -// time.Sleep(500 * time.Millisecond) -// } -// require.NoError(t, err) -//} -// -////nolint:funlen //This is a test -//func TestClientTLS(t *testing.T) { -// t.Skip("The test fails because the logic for generating the group has changed") -// lg := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// tmpPath := path.Join(t.TempDir(), "drand") -// require.NoError(t, os.Mkdir(tmpPath, 0o740)) -// -// groupPath := path.Join(tmpPath, "group.toml") -// certPath := path.Join(tmpPath, "server.pem") -// keyPath := path.Join(tmpPath, "key.pem") -// pubPath := path.Join(tmpPath, "pub.key") -// -// freePort := test.FreePort() -// addr := "127.0.0.1:" + freePort -// ctrlPort := test.FreePort() -// metricsPort := test.FreePort() -// -// priv, err := key.NewTLSKeyPair(addr, nil) -// require.NoError(t, err) -// require.NoError(t, key.Save(pubPath, priv.Public, false)) -// -// config := core.NewConfig(lg, core.WithConfigFolder(tmpPath)) -// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) -// err = fileStore.SaveKeyPair(priv) -// require.NoError(t, err) -// -// if httpscerts.Check(certPath, keyPath) != nil { -// t.Log("generating on the fly") -// h, _, err := gnet.SplitHostPort(priv.Public.Address()) -// require.NoError(t, err) -// err = httpscerts.Generate(certPath, keyPath, h) -// require.NoError(t, err) -// } -// -// // fake group -// _, group := test.BatchTLSIdentities(5, sch, beaconID) -// // fake dkg outuput -// fakeKey := sch.KeyGroup.Point().Pick(random.New()) -// // need a threshold of coefficients -// distKey := &key.DistPublic{ -// Coefficients: []kyber.Point{ -// fakeKey, -// sch.KeyGroup.Point().Pick(random.New()), -// sch.KeyGroup.Point().Pick(random.New()), -// }, -// } -// group.Nodes[0] = &key.Node{Identity: priv.Public, Index: 0} -// group.Period = 2 * time.Minute -// group.GenesisTime = time.Now().Unix() -// group.PublicKey = distKey -// require.NoError(t, fileStore.SaveGroup(group)) -// require.NoError(t, key.Save(groupPath, group, false)) -// -// // fake share -// scalarOne := sch.KeyGroup.Scalar().One() -// s := &share.PriShare{I: 2, V: scalarOne} -// // TODO: check DistKeyShare if it needs a scheme -// fakeShare := &key.Share{DistKeyShare: dkg.DistKeyShare{Share: s}, Scheme: sch} -// err = fileStore.SaveShare(fakeShare) -// require.NoError(t, err) -// -// startArgs := []string{ -// "drand", -// "start", -// "--private-listen", priv.Public.Address(), -// "--tls-cert", certPath, -// "--tls-key", keyPath, -// "--control", ctrlPort, -// "--folder", tmpPath, -// "--metrics", metricsPort, -// } -// go func() { -// err := CLI().Run(startArgs) -// if err != nil { -// t.Errorf("error while starting node: %v", err) -// } -// }() -// -// stopArgs := []string{"drand", "stop", "--control", ctrlPort} -// defer func() { -// err := CLI().Run(stopArgs) -// if err != nil { -// t.Errorf("error while stopping the node: %v", err) -// } -// }() -// -// time.Sleep(500 * time.Millisecond) -// -// testStartedTLSDrandFunctional(t, ctrlPort, certPath, group, priv) -//} -// -//func testStartedTLSDrandFunctional(t *testing.T, ctrlPort, certPath string, group *key.Group, priv *key.Pair) { -// t.Helper() -// lg := log.New(nil, log.DebugLevel, true) -// -// var err error -// -// chainInfoCmd := []string{"drand", "get", "chain-info", "--tls-cert", certPath, priv.Public.Address()} -// chainInfoBuff, err := json.MarshalIndent(chain2.NewChainInfo(lg, group).ToProto(nil), "", " ") -// require.NoError(t, err) -// expectedOutput := string(chainInfoBuff) -// testCommand(t, chainInfoCmd, expectedOutput) -// -// showPublic := []string{"drand", "show", "public", "--control", ctrlPort} -// b, _ := priv.Public.Key.MarshalBinary() -// exp := hex.EncodeToString(b) -// testCommand(t, showPublic, exp) -// -// showCokey := []string{"drand", "show", "chain-info", "--control", ctrlPort} -// expectedOutput = string(chainInfoBuff) -// testCommand(t, showCokey, expectedOutput) -// -// showGroup := []string{"drand", "show", "group", "--control", ctrlPort} -// testCommand(t, showGroup, "") -// -// showHash := []string{"drand", "show", "group", "--control", ctrlPort, "--hash"} -// groupHash := hex.EncodeToString(group.Hash()) -// testCommand(t, showHash, groupHash) -//} -// -//func testCommand(t *testing.T, args []string, exp string) { -// t.Helper() -// -// var buff bytes.Buffer -// t.Log("--------------") -// cli := CLI() -// cli.Writer = &buff -// require.NoError(t, cli.Run(args)) -// if exp == "" { -// return -// } -// t.Logf("RUNNING: %v\n", args) -// require.Contains(t, strings.Trim(buff.String(), "\n"), exp) -//} -// -//// getSBFolderStructure create a new single-beacon folder structure in a temporary folder -//func getSBFolderStructure(t *testing.T) string { -// t.Helper() -// -// tmp := path.Join(t.TempDir(), "drand") -// -// fs.CreateSecureFolder(path.Join(tmp, key.GroupFolderName)) -// fs.CreateSecureFolder(path.Join(tmp, key.FolderName)) -// fs.CreateSecureFolder(path.Join(tmp, core.DefaultDBFolder)) -// -// return tmp -//} -// -//func TestDrandListSchemes(t *testing.T) { -// n := 2 -// instances := genAndLaunchDrandInstances(t, n) -// -// for _, instance := range instances { -// remote := []string{"drand", "util", "list-schemes", "--control", instance.ctrlPort} -// -// err := CLI().Run(remote) -// require.NoError(t, err) -// } -//} -// -//func TestDrandReloadBeacon(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// -// for i, inst := range instances { -// if i == 0 { -// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) -// } else { -// inst.join(t, beaconID) -// } -// } -// instances[0].executeDKG(t, beaconID) -// -// dkgTimeoutSeconds := 20 -// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) -// t.Log("waiting for initial set up to settle on all nodes") -// -// defer func() { -// for _, inst := range instances { -// // We want to ignore this error, at least until the stop command won't return an error -// // when correctly running the stop command. -// t.Logf("stopping instance %v\n", inst.addr) -// err := inst.stopAll() -// require.NoError(t, err) -// t.Logf("stopped instance %v\n", inst.addr) -// } -// }() -// -// t.Log("waiting for initial setup to finish") -// time.Sleep(5 * time.Second) -// -// // try to reload a beacon which is already loaded -// err = instances[3].load(beaconID) -// require.Error(t, err) -// -// // Stop beacon process... not the entire node -// err = instances[3].stop(beaconID) -// require.NoError(t, err) -// -// // check the node is still alive -// testPing(t, instances[3].ctrlPort) -// -// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") -// time.Sleep(10 * time.Second) -// -// // reload a beacon -// err = instances[3].load(beaconID) -// require.NoError(t, err) -// -// // test beacon process status -// testStatus(t, instances[3].ctrlPort, beaconID) -// -// time.Sleep(3 * time.Second) -// -// // test beacon process status -// testStatus(t, instances[3].ctrlPort, beaconID) -//} -// -//func TestDrandLoadNotPresentBeacon(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// -// for i, inst := range instances { -// if i == 0 { -// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) -// } else { -// inst.join(t, beaconID) -// } -// } -// instances[0].executeDKG(t, beaconID) -// -// dkgTimeoutSeconds := 20 -// -// t.Log("waiting for initial set up to settle on all nodes") -// err = instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds) -// if err != nil { -// t.Fatal(err) -// } -// -// defer func() { -// for _, inst := range instances { -// _ = inst.stopAll() -// } -// }() -// -// t.Log("waiting for initial setup to finish") -// time.Sleep(5 * time.Second) -// -// // Stop beacon process... not the entire node -// err = instances[3].stop(beaconID) -// require.NoError(t, err) -// -// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") -// time.Sleep(10 * time.Second) -// -// // reload a different beacon -// err = instances[3].load("not-a-valid-beacon-name-here") -// require.Error(t, err) -// -// // test original beacon process status and hope it's still off -// testFailStatus(t, instances[3].ctrlPort, beaconID) -//} -// -//func TestDrandStatus_WithoutDKG(t *testing.T) { -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// allAddresses := make([]string, 0, n) -// for _, instance := range instances { -// allAddresses = append(allAddresses, instance.addr) -// } -// -// // check that each node can reach each other -// for i, instance := range instances { -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// remote = append(remote, allAddresses...) -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } -// } -// // stop one and check that all nodes report this node down -// toStop := 2 -// insToStop := instances[toStop] -// err := insToStop.stopAll() -// require.NoError(t, err) -// -// for i, instance := range instances { -// if i == toStop { -// continue -// } -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// remote = append(remote, allAddresses...) -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// if j != toStop { -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } else { -// require.Contains(t, buff.String(), instance.addr+" -> X") -// } -// } -// } -//} -// -//func TestDrandStatus_WithDKG_NoAddress(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping slow test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// -// for i, inst := range instances { -// if i == 0 { -// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) -// } else { -// inst.join(t, beaconID) -// } -// } -// instances[0].executeDKG(t, beaconID) -// -// dkgTimeoutSeconds := 20 -// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) -// t.Log("waiting for initial set up to settle on all nodes") -// -// // check that each node can reach each other -// for i, instance := range instances { -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } -// } -// // stop one and check that all nodes report this node down -// toStop := 2 -// insToStop := instances[toStop] -// err = insToStop.stopAll() -// require.NoError(t, err) -// -// for i, instance := range instances { -// if i == toStop { -// continue -// } -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// if j != toStop { -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } else { -// require.Contains(t, buff.String(), instance.addr+" -> X") -// } -// } -// } -//} -// -//func TestDrandStatus_WithDKG_OneAddress(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping slow test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// -// for i, inst := range instances { -// if i == 0 { -// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) -// } else { -// inst.join(t, beaconID) -// } -// } -// instances[0].executeDKG(t, beaconID) -// -// dkgTimeoutSeconds := 20 -// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) -// t.Log("waiting for initial set up to settle on all nodes") -// -// // check that each node can reach each other -// for i, instance := range instances { -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// remote = append(remote, instances[i].addr) -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } -// } -// // stop one and check that all nodes report this node down -// toStop := 2 -// insToStop := instances[toStop] -// err = insToStop.stopAll() -// require.NoError(t, err) -// -// for i, instance := range instances { -// if i == toStop { -// continue -// } -// remote := []string{"drand", "util", "remote-status", "--control", instance.ctrlPort} -// remote = append(remote, instances[i].addr) -// var buff bytes.Buffer -// -// cli := CLI() -// cli.Writer = &buff -// -// err := cli.Run(remote) -// require.NoError(t, err) -// for j, instance := range instances { -// if i == j { -// continue -// } -// if j != toStop { -// require.Contains(t, buff.String(), instance.addr+" -> OK") -// } else { -// require.Contains(t, buff.String(), instance.addr+" -> X") -// } -// } -// } -//} -// -//func TestEmptyPortSelectionUsesDefaultDuringKeygen(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := t.TempDir() -// app := CLI() -// -// // args are missing a port for the node address -// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} -// // after being prompted for a port, the 'user' hits enter to select the default -// app.Reader = strings.NewReader("\n") -// -// require.NoError(t, app.Run(args)) -//} -// -//func TestValidPortSelectionSucceedsDuringKeygen(t *testing.T) { -// beaconID := test.GetBeaconIDFromEnv() -// -// tmp := t.TempDir() -// app := CLI() -// -// args := []string{"drand", "generate-keypair", "--folder", tmp, "--id", beaconID, "127.0.0.1"} -// app.Reader = strings.NewReader("8080\n") -// -// require.NoError(t, app.Run(args)) -//} -// -//type drandInstance struct { -// path string -// ctrlPort string -// addr string -// metrics string -// certPath string -// keyPath string -// certsDir string -//} -// -//func (d *drandInstance) stopAll() error { -// return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort}) -//} -// -//func (d *drandInstance) stop(beaconID string) error { -// return CLI().Run([]string{"drand", "stop", "--control", d.ctrlPort, "--id", beaconID}) -//} -// -//func (d *drandInstance) startInitialDKG( -// t *testing.T, -// l log.Logger, -// instances []*drandInstance, -// threshold, -// //nolint:unparam // This is a parameter -// periodSeconds int, -// beaconID string, -// sch *crypto.Scheme, -//) { -// t.Helper() -// -// addrs := make([]string, len(instances)) -// for i, v := range instances { -// addrs[i] = v.ctrlPort -// } -// -// proposal, err := generateJoiningProposal(l, "default", addrs) -// require.NoError(t, err) -// -// proposalPath := filepath.Join(t.TempDir(), "proposal.toml") -// err = os.WriteFile(proposalPath, []byte(proposal), 0755) -// require.NoError(t, err) -// -// dkgArgs := []string{ -// "drand", -// "dkg", -// "propose", -// "--proposal", proposalPath, -// "--transition-time", fmt.Sprintf("%ds", 30*periodSeconds), -// "--catchup-period", fmt.Sprintf("%ds", periodSeconds/2), -// "--threshold", fmt.Sprintf("%d", threshold), -// "--period", fmt.Sprintf("%ds", periodSeconds), -// "--control", d.ctrlPort, -// "--scheme", sch.Name, -// "--id", beaconID, -// } -// -// err = CLI().Run(dkgArgs) -// require.NoError(t, err) -//} -// -//func (d *drandInstance) executeDKG(t *testing.T, beaconID string) { -// t.Helper() -// dkgArgs := []string{ -// "drand", -// "dkg", -// "execute", -// "--control", d.ctrlPort, -// "--id", beaconID, -// } -// -// err := CLI().Run(dkgArgs) -// require.NoError(t, err) -//} -// -//func (d *drandInstance) awaitDKGComplete( -// t *testing.T, -// beaconID string, -// //nolint:unparam // This is a parameter -// epoch uint32, -// timeoutSeconds int, -//) error { -// t.Helper() -// dkgArgs := []string{ -// "drand", -// "dkg", -// "status", -// "--control", d.ctrlPort, -// "--id", beaconID, -// "--format", "csv", -// } -// -// for i := 0; i < timeoutSeconds; i++ { -// cli := CLI() -// var buf bytes.Buffer -// cli.Writer = &buf -// -// err := cli.Run(dkgArgs) -// if err != nil { -// return err -// } -// -// statusOutput := buf.String() -// expected := fmt.Sprintf("State:Complete,Epoch:%d,", epoch) -// -// if strings.Contains(statusOutput, expected) { -// return nil -// } -// time.Sleep(1 * time.Second) -// } -// -// return errors.New("DKG didn't complete within the timeout") -//} -// -//func (d *drandInstance) load(beaconID string) error { -// reloadArgs := []string{ -// "drand", -// "load", -// "--control", d.ctrlPort, -// "--id", beaconID, -// } -// -// return CLI().Run(reloadArgs) -//} -// -//func (d *drandInstance) run(t *testing.T, beaconID string) { -// t.Helper() -// -// d.runWithStartArgs(t, beaconID, nil) -//} -// -//func (d *drandInstance) runWithStartArgs(t *testing.T, beaconID string, startArgs []string) { -// t.Helper() -// -// require.Equal(t, 0, len(startArgs)%2, "start args must be in pairs of option/value") -// -// baseArgs := []string{ -// "drand", -// "start", -// "--verbose", -// "--tls-cert", d.certPath, -// "--tls-key", d.keyPath, -// "--certs-dir", d.certsDir, -// "--control", d.ctrlPort, -// "--folder", d.path, -// "--metrics", d.metrics, -// "--private-listen", d.addr, -// } -// -// baseArgs = append(baseArgs, startArgs...) -// -// go func() { -// err := CLI().Run(baseArgs) -// require.NoError(t, err) -// }() -// -// // Prevent race condition in urfave/cli -// time.Sleep(100 * time.Millisecond) -// -// // make sure we run each one sequentially -// testStatus(t, d.ctrlPort, beaconID) -//} -// -//func (d *drandInstance) join(t *testing.T, id string) { -// t.Helper() -// joinArgs := []string{ -// "drand", -// "dkg", -// "join", -// "--id", -// id, -// "--control", -// d.ctrlPort, -// } -// -// err := CLI().Run(joinArgs) -// require.NoError(t, err) -//} -// -//func genAndLaunchDrandInstances(t *testing.T, n int) []*drandInstance { -// t.Helper() -// -// beaconID := test.GetBeaconIDFromEnv() -// -// ins := genDrandInstances(t, beaconID, n) -// return launchDrandInstances(t, beaconID, ins) -//} -// -//func genDrandInstances(t *testing.T, beaconID string, n int) []*drandInstance { -// t.Helper() -// -// tmpPath := t.TempDir() -// -// certsDir := path.Join(tmpPath, "certs") -// require.NoError(t, os.Mkdir(certsDir, 0o740)) -// l := log.New(nil, log.DebugLevel, true) -// -// ins := make([]*drandInstance, 0, n) -// for i := 1; i <= n; i++ { -// nodePath, err := os.MkdirTemp(tmpPath, "node") -// require.NoError(t, err) -// -// certPath := path.Join(nodePath, "cert") -// keyPath := path.Join(nodePath, "tls.key") -// pubPath := path.Join(tmpPath, "pub.key") -// -// freePort := test.FreePort() -// addr := "127.0.0.1:" + freePort -// ctrlPort := test.FreePort() -// metricsPort := test.FreePort() -// -// // generate key so it loads -// // TODO let's remove this requirement - no need for longterm keys -// priv, err := key.NewTLSKeyPair(addr, nil) -// require.NoError(t, err) -// require.NoError(t, key.Save(pubPath, priv.Public, false)) -// config := core.NewConfig(l, core.WithConfigFolder(nodePath)) -// fileStore := key.NewFileStore(config.ConfigFolderMB(), beaconID) -// err = fileStore.SaveKeyPair(priv) -// require.NoError(t, err) -// -// h, _, err := gnet.SplitHostPort(addr) -// require.NoError(t, err) -// -// err = httpscerts.Generate(certPath, keyPath, h) -// require.NoError(t, err) -// -// // copy into one folder for giving a common CERT folder -// _, err = exec.Command("cp", certPath, path.Join(certsDir, fmt.Sprintf("cert-%d", i))).Output() -// require.NoError(t, err) -// -// ins = append(ins, &drandInstance{ -// addr: addr, -// ctrlPort: ctrlPort, -// path: nodePath, -// keyPath: keyPath, -// metrics: metricsPort, -// certPath: certPath, -// certsDir: certsDir, -// }) -// } -// -// return ins -//} -// -//func launchDrandInstances(t *testing.T, beaconID string, ins []*drandInstance) []*drandInstance { -// t.Helper() -// -// for _, instance := range ins { -// instance.run(t, beaconID) -// } -// return ins -//} -// -////nolint:funlen // This is a test -//func TestMemDBBeaconReJoinsNetworkAfterLongStop(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// // How many rounds to generate while the node is stopped. -// roundsWhileMissing := 50 -// period := 1 -// n := 4 -// instances := genDrandInstances(t, beaconID, n) -// memDBNodeID := len(instances) - 1 -// -// for i := 0; i < memDBNodeID; i++ { -// inst := instances[i] -// inst.run(t, beaconID) -// } -// -// instances[memDBNodeID].runWithStartArgs(t, beaconID, []string{"--db", "memdb"}) -// memDBNode := instances[memDBNodeID] -// -// for i, inst := range instances { -// inst := inst -// if i == 0 { -// inst.startInitialDKG(t, l, instances, 3, period, beaconID, sch) -// // Wait a bit after launching the leader to launch the other nodes too. -// time.Sleep(500 * time.Millisecond) -// } else { -// inst.join(t, beaconID) -// } -// } -// -// instances[0].executeDKG(t, beaconID) -// -// t.Log("waiting for initial set up to settle on all nodes") -// err = instances[0].awaitDKGComplete(t, beaconID, 1, 60) -// require.NoError(t, err) -// -// defer func() { -// for _, inst := range instances { -// // We want to ignore this error, at least until the stop command won't return an error -// // when correctly running the stop command. -// t.Logf("stopping instance %v\n", inst.addr) -// err := inst.stopAll() -// require.NoError(t, err) -// t.Logf("stopped instance %v\n", inst.addr) -// } -// }() -// -// memDBClient, err := net.NewControlClient(l, memDBNode.ctrlPort) -// require.NoError(t, err) -// -// chainInfo, err := memDBClient.ChainInfo(beaconID) -// require.NoError(t, err) -// -// // Wait until DKG finishes -// secondsToGenesisTime := chainInfo.GenesisTime - time.Now().Unix() -// t.Logf("waiting %ds until DKG finishes\n", secondsToGenesisTime) -// time.Sleep(time.Duration(secondsToGenesisTime) * time.Second) -// -// // Wait for some rounds to be generated -// t.Log("wait for some rounds to be generated") -// time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) -// -// // Get the status before stopping the node -// status, err := memDBClient.Status(beaconID) -// require.NoError(t, err) -// -// require.False(t, status.ChainStore.IsEmpty) -// require.NotZero(t, status.ChainStore.LastRound) -// -// lastRoundBeforeShutdown := status.ChainStore.LastRound -// -// // Stop beacon process... not the entire node -// err = instances[memDBNodeID].stop(beaconID) -// require.NoError(t, err) -// -// t.Log("waiting for beacons to be generated while a beacon process is stopped on a node") -// time.Sleep(time.Duration(roundsWhileMissing*period) * time.Second) -// -// // reload a beacon -// err = instances[memDBNodeID].load(beaconID) -// require.NoError(t, err) -// -// // Wait a bit to allow the node to startup and load correctly -// time.Sleep(2 * time.Second) -// -// status, err = memDBClient.Status(beaconID) -// require.NoError(t, err) -// -// require.False(t, status.ChainStore.IsEmpty) -// require.NotZero(t, status.ChainStore.LastRound) -// expectedRound := lastRoundBeforeShutdown + uint64(roundsWhileMissing) -// t.Logf("comparing lastRound %d with lastRoundBeforeShutdown %d\n", status.ChainStore.LastRound, expectedRound) -// require.GreaterOrEqual(t, status.ChainStore.LastRound, expectedRound) -//} -// -//func TestDKGStatusDoesntBlowUp(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// -// l := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// beaconID := test.GetBeaconIDFromEnv() -// -// // start some nodes -// n := 4 -// instances := genAndLaunchDrandInstances(t, n) -// -// // execute a DKG -// for i, inst := range instances { -// if i == 0 { -// inst.startInitialDKG(t, l, instances, n, 1, beaconID, sch) -// } else { -// inst.join(t, beaconID) -// } -// } -// instances[0].executeDKG(t, beaconID) -// -// // wait for the DKG to finish -// dkgTimeoutSeconds := 20 -// require.NoError(t, instances[0].awaitDKGComplete(t, beaconID, 1, dkgTimeoutSeconds)) -// t.Log("waiting for initial set up to settle on all nodes") -// -// // check the status command runs fine -// err = CLI().Run([]string{"drand", "dkg", "status", "--control", instances[0].ctrlPort}) -// require.NoError(t, err) -//} +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClientTLS(t *testing.T) { + addr := "https://api.drand.sh" + + chainInfoCmd := []string{"drand", "get", "chain-info", "--url", addr, "--insecure"} + expectedInOutput := "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce" + testCommand(t, chainInfoCmd, expectedInOutput) + + showHash := []string{"drand", "get", "public", "--url", addr, "--insecure"} + round1 := "101297f1ca7dc44ef6088d94ad5fb7ba03455dc33d53ddb412bbc4564ed986ec" + testCommand(t, showHash, round1) +} + +func testCommand(t *testing.T, args []string, exp string) { + t.Helper() + + var buff bytes.Buffer + t.Log("--------------") + cli := CLI() + cli.Writer = &buff + require.NoError(t, cli.Run(args)) + if exp == "" { + return + } + t.Logf("RUNNING: %v\n", args) + require.Contains(t, strings.Trim(buff.String(), "\n"), exp) +} diff --git a/internal/grpc/client_test.go b/internal/grpc/client_test.go index 113e8a8..6121bae 100644 --- a/internal/grpc/client_test.go +++ b/internal/grpc/client_test.go @@ -3,12 +3,14 @@ package grpc import ( "bytes" "context" - "github.com/drand/drand/v2/common/log" - clock "github.com/jonboulle/clockwork" "sync" "testing" "time" + clock "github.com/jonboulle/clockwork" + + "github.com/drand/drand/v2/common/log" + "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 0b6c0d5..459511d 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -11,7 +11,6 @@ import ( "strings" "github.com/BurntSushi/toml" - "github.com/drand/drand/v2/common/key" "github.com/google/uuid" bds "github.com/ipfs/go-ds-badger2" clock "github.com/jonboulle/clockwork" @@ -19,6 +18,8 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" + "github.com/drand/drand/v2/common/key" + pubClient "github.com/drand/drand-cli/client" http2 "github.com/drand/drand-cli/client/http" gclient "github.com/drand/drand-cli/client/lp2p" @@ -95,14 +96,12 @@ var ( // ClientFlags is a list of common flags for client creation var ClientFlags = []cli.Flag{ URLFlag, - GRPCConnectFlag, HashFlag, HashListFlag, GroupConfListFlag, GroupConfFlag, InsecureFlag, RelayFlag, - PortFlag, JSONFlag, } @@ -111,7 +110,7 @@ var ClientFlags = []cli.Flag{ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) (client.Client, error) { ctx := c.Context clients := make([]client.Client, 0) - l := log.DefaultLogger() + l := log.New(nil, log.DebugLevel, false) var info *chainCommon.Info var err error diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 7c9e68b..58089c1 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -68,10 +68,10 @@ func TestClientLib(t *testing.T) { go grpcLis.Start() defer grpcLis.Stop(context.Background()) - args := []string{"mock-client", "--url", "http://" + addr, "--grpc-connect", grpcLis.Addr(), "--insecure"} + args := []string{"mock-client", "--url", "http://" + addr, "--insecure"} err = run(lg, args) if err != nil { - t.Fatal("GRPC should work", err) + t.Fatal("HTTP should work", err) } args = []string{"mock-client", "--url", "https://" + addr} @@ -155,14 +155,6 @@ func TestClientLibChainHashOverrideError(t *testing.T) { } } -func TestClientLibListenPort(t *testing.T) { - lg := log.New(nil, log.DebugLevel, true) - err := run(lg, []string{"mock-client", "--relay", fakeGossipRelayAddr, "--port", "0.0.0.0:0", "--group-conf", groupTOMLPath()}) - if err != nil { - t.Fatal(err) - } -} - func groupTOMLPath() string { _, file, _, ok := runtime.Caller(0) if !ok { diff --git a/internal/lp2p/ctor_test.go b/internal/lp2p/ctor_test.go index 0f2e2c4..f42ebf9 100644 --- a/internal/lp2p/ctor_test.go +++ b/internal/lp2p/ctor_test.go @@ -2,9 +2,10 @@ package lp2p import ( "fmt" - "github.com/drand/drand/v2/common/log" "path" "testing" + + "github.com/drand/drand/v2/common/log" ) func TestCreateThenLoadPrivKey(t *testing.T) { diff --git a/internal/lp2p/relaynode_test.go b/internal/lp2p/relaynode_test.go index 256ab41..d79db7e 100644 --- a/internal/lp2p/relaynode_test.go +++ b/internal/lp2p/relaynode_test.go @@ -9,10 +9,11 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/drand/drand/v2/common/key" "github.com/drand/drand/v2/common/log" "github.com/drand/drand/v2/crypto" - "github.com/stretchr/testify/require" "github.com/drand/drand-cli/client" "github.com/drand/drand-cli/client/test/result/mock" diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go new file mode 100644 index 0000000..3670b56 --- /dev/null +++ b/internal/metrics/metrics.go @@ -0,0 +1,462 @@ +package metrics + +import ( + "context" + "fmt" + "net" + "net/http" + "runtime" + "strings" + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + + common2 "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/log" +) + +var ( + // PrivateMetrics about the internal world (go process, private stuff) + PrivateMetrics = prometheus.NewRegistry() + // HTTPMetrics about the public surface area (http requests, cdn stuff) + HTTPMetrics = prometheus.NewRegistry() + // GroupMetrics about the group surface (grp, group-member stuff) + GroupMetrics = prometheus.NewRegistry() + // ClientMetrics about the drand client requests to servers + ClientMetrics = prometheus.NewRegistry() + + // APICallCounter (Group) how many grpc calls + APICallCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "api_call_counter", + Help: "Number of API calls that we have received", + }, []string{"api_method"}) + + // GroupDialFailures (Group) how many failures connecting outbound + GroupDialFailures = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "dial_failures", + Help: "Number of times there have been network connection issues", + }, []string{"peer_address"}) + + // OutgoingConnections (Group) how many GrpcClient connections are present + OutgoingConnections = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "outgoing_group_connections", + Help: "Number of peers with current outgoing GrpcClient connections", + }) + + GroupSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "group_size", + Help: "Number of peers in the current group", + }, []string{"beacon_id"}) + + GroupThreshold = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "group_threshold", + Help: "Number of shares needed for beacon reconstruction", + }, []string{"beacon_id"}) + + // BeaconDiscrepancyLatency (Group) millisecond duration between time beacon created and + // calculated time of round. + BeaconDiscrepancyLatency = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "beacon_discrepancy_latency", + Help: "Discrepancy between beacon creation time and calculated round time", + }, []string{"beacon_id"}) + + // LastBeaconRound is the most recent round (as also seen at /health) stored. + LastBeaconRound = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "last_beacon_round", + Help: "Last locally stored beacon", + }, []string{"beacon_id"}) + + // HTTPCallCounter (HTTP) how many http requests + HTTPCallCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "http_call_counter", + Help: "Number of HTTP calls received", + }, []string{"code", "method"}) + // HTTPLatency (HTTP) how long http request handling takes + HTTPLatency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "http_response_duration", + Help: "histogram of request latencies", + Buckets: prometheus.DefBuckets, + ConstLabels: prometheus.Labels{"handler": "http"}, + }, []string{"method"}) + // HTTPInFlight (HTTP) how many http requests exist + HTTPInFlight = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "http_in_flight", + Help: "A gauge of requests currently being served.", + }) + + // Client observation metrics + + // ClientWatchLatency measures the latency of the watch channel from the client's perspective. + ClientWatchLatency = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "client_watch_latency", + Help: "Duration between time round received and time round expected.", + }) + + // ClientHTTPHeartbeatSuccess measures the success rate of HTTP hearbeat randomness requests. + ClientHTTPHeartbeatSuccess = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "client_http_heartbeat_success", + Help: "Number of successful HTTP heartbeats.", + }, []string{"http_address"}) + + // ClientHTTPHeartbeatFailure measures the number of times HTTP heartbeats fail. + ClientHTTPHeartbeatFailure = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "client_http_heartbeat_failure", + Help: "Number of unsuccessful HTTP heartbeats.", + }, []string{"http_address"}) + + // ClientHTTPHeartbeatLatency measures the randomness latency of an HTTP source. + ClientHTTPHeartbeatLatency = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "client_http_heartbeat_latency", + Help: "Randomness latency of an HTTP source.", + }, []string{"http_address"}) + + // ClientInFlight measures how many active requests have been made + ClientInFlight = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "client_in_flight", + Help: "A gauge of in-flight drand client http requests.", + }, + []string{"url"}, + ) + + // ClientRequests measures how many total requests have been made + ClientRequests = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "client_api_requests_total", + Help: "A counter for requests from the drand client.", + }, + []string{"code", "method", "url"}, + ) + + // ClientDNSLatencyVec tracks the observed DNS resolution times + ClientDNSLatencyVec = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "client_dns_duration_seconds", + Help: "Client drand dns latency histogram.", + Buckets: []float64{.005, .01, .025, .05}, + }, + []string{"event", "url"}, + ) + + // ClientTLSLatencyVec tracks observed TLS connection times + ClientTLSLatencyVec = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "client_tls_duration_seconds", + Help: "Client drand tls latency histogram.", + Buckets: []float64{.05, .1, .25, .5}, + }, + []string{"event", "url"}, + ) + + // ClientLatencyVec tracks raw http request latencies + ClientLatencyVec = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "client_request_duration_seconds", + Help: "A histogram of client request latencies.", + Buckets: prometheus.DefBuckets, + }, + []string{"url"}, + ) + + dkgEpoch = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "dkg_epoch", + Help: "The epoch of any currently in progress or completed DKGs", + }, + []string{"beacon_id"}, + ) + + // dkgState (Group) tracks DKG status changes + dkgState = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "dkg_state", + Help: "DKG state: 0-Not Started, 1-Waiting, 2-In Progress, 3-Done, 4-Unknown, 5-Shutdown", + }, []string{"beacon_id"}) + + // DKGStateTimestamp (Group) tracks the time when the reshare status changes + dkgStateTimestamp = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "dkg_state_timestamp", + Help: "Timestamp when the DKG state last changed", + }, []string{"beacon_id"}) + + // dkgLeader (Group) tracks whether this node is the leader during DKG + dkgLeader = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "dkg_leader", + Help: "Is this node the leader during DKG? 0-false, 1-true", + }, []string{"beacon_id"}) + + // reshareState (Group) tracks reshare status changes + reshareState = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "reshare_state", + Help: "Reshare state: 0-Idle, 1-Waiting, 2-In Progress, 3-Unknown, 4-Shutdown", + }, []string{"beacon_id"}) + + // reshareStateTimestamp (Group) tracks the time when the reshare status changes + reshareStateTimestamp = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "reshare_state_timestamp", + Help: "Timestamp when the reshare state last changed", + }, []string{"beacon_id"}) + + // reshareLeader (Group) tracks whether this node is the leader during Reshare + reshareLeader = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "reshare_leader", + Help: "Is this node the leader during Reshare? 0-false, 1-true", + }, []string{"beacon_id"}) + + // drandBuildTime (Group) emits the timestamp when the binary was built in Unix time. + drandBuildTime = prometheus.NewUntypedFunc(prometheus.UntypedOpts{ + Name: "drand_build_time", + Help: "Timestamp when the binary was built in seconds since the Epoch", + ConstLabels: map[string]string{"build": common2.COMMIT, "version": common2.GetAppVersion().String()}, + }, func() float64 { return float64(getBuildTimestamp(common2.BUILDDATE)) }) + + // IsDrandNode (Group) is 1 for drand nodes, 0 for relays + IsDrandNode = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "is_drand_node", + Help: "1 for drand nodes, not emitted for relays", + }) + + // DrandStorageBackend reports the database the node is running with + DrandStorageBackend = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "drand_node_db", + Help: "The database type the node is running with. 1=bolt-trimmed, 2=postgres, 3=memdb, 4=bolt-untrimmed", + }, []string{"beaconID", "db_type"}) + + // OutgoingConnectionState (Group) tracks the state of an outgoing connection, using the states from + // https://github.com/grpc/grpc-go/blob/8075dd35d2738b352c4355b4b353dc1e9183bea7/connectivity/connectivity.go#L51-L62 + // Due to the fact that grpc-go doesn't support adding a listener for state tracking, this is + // emitted only when getting a connection to the remote host. This means that: + // * If a non-PL host is unable to connect to a PL host, the metric will not be sent to InfluxDB + // * The state might not be up to date (e.g. the remote host is disconnected but we haven't + // tried to connect to it) + OutgoingConnectionState = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "outgoing_connection_state", + Help: "State of an outgoing connection. 0=Idle, 1=Connecting, 2=Ready, 3=Transient Failure, 4=Shutdown", + }, []string{"remote_host"}) + + // DrandStartTimestamp (group) contains the timestamp in seconds since the epoch of the drand process startup + DrandStartTimestamp = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "drand_start_timestamp", + Help: "Timestamp when the drand process started up in seconds since the Epoch", + }) + + ErrorSendingPartialCounter = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "error_sending_partial", + Help: "Number of errors sending partial beacons to nodes. A good proxy for whether nodes are up or down. " + + "1 = Error occurred, 0 = No error occurred", + }, []string{"beaconID", "address"}) + + metricsBound sync.Once +) + +func bindMetrics(l log.Logger) { + // The private go-level metrics live in private. + if err := PrivateMetrics.Register(collectors.NewGoCollector()); err != nil { + l.Errorw("error in bindMetrics", "metrics", "goCollector", "err", err) + return + } + if err := PrivateMetrics.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})); err != nil { + l.Errorw("error in bindMetrics", "metrics", "processCollector", "err", err) + return + } + + // Group metrics + group := []prometheus.Collector{ + APICallCounter, + GroupDialFailures, + OutgoingConnections, + GroupSize, + GroupThreshold, + BeaconDiscrepancyLatency, + LastBeaconRound, + drandBuildTime, + dkgState, + dkgStateTimestamp, + dkgLeader, + reshareState, + reshareStateTimestamp, + reshareLeader, + OutgoingConnectionState, + IsDrandNode, + DrandStartTimestamp, + DrandStorageBackend, + ErrorSendingPartialCounter, + } + for _, c := range group { + if err := GroupMetrics.Register(c); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } + if err := PrivateMetrics.Register(c); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } + } + + // HTTP metrics + httpMetrics := []prometheus.Collector{ + HTTPCallCounter, + HTTPLatency, + HTTPInFlight, + } + for _, c := range httpMetrics { + if err := HTTPMetrics.Register(c); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } + if err := PrivateMetrics.Register(c); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } + } + + // Client metrics + if err := RegisterClientMetrics(ClientMetrics); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } + if err := RegisterClientMetrics(PrivateMetrics); err != nil { + l.Errorw("error in bindMetrics", "metrics", "bindMetrics", "err", err) + return + } +} + +// RegisterClientMetrics registers drand client metrics with the given registry +func RegisterClientMetrics(r prometheus.Registerer) error { + // Client metrics + client := []prometheus.Collector{ + ClientDNSLatencyVec, + ClientInFlight, + ClientLatencyVec, + ClientRequests, + ClientTLSLatencyVec, + ClientWatchLatency, + ClientHTTPHeartbeatSuccess, + ClientHTTPHeartbeatFailure, + ClientHTTPHeartbeatLatency, + } + for _, c := range client { + if err := r.Register(c); err != nil { + return err + } + } + return nil +} + +// Handler abstracts a helper for relaying http requests to a group peer +type Handler func(ctx context.Context, addr string) (http.Handler, error) + +// Client is the same as net.MetricsClient but avoids cyclic dependencies in our metric and net code. +type Client interface { + GetMetrics(ctx context.Context, p string) (string, error) +} + +// Start starts a prometheus metrics server with debug endpoints. If metricsBind is 0 it will use an available port. +func Start(logger log.Logger, metricsBind string, pprof http.Handler, cli Client) net.Listener { + logger.Infow("metrics starting", "desired_port", metricsBind) + + metricsBound.Do(func() { + bindMetrics(logger) + }) + + // handle metricsBind being just a port value + if !strings.Contains(metricsBind, ":") { + metricsBind = "127.0.0.1:" + metricsBind + } + l, err := net.Listen("tcp", metricsBind) + if err != nil { + logger.Warnw("", "metrics", "listen failed", "err", err) + return nil + } + logger.Infow("metric listener started", "addr", l.Addr()) + + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.HandlerFor(PrivateMetrics, promhttp.HandlerOpts{Registry: PrivateMetrics})) + + mux.Handle("/peer/", newRemotePeerHandler(logger, cli)) + + if pprof != nil { + mux.Handle("/debug/pprof/", pprof) + } + + mux.HandleFunc("/debug/gc", func(w http.ResponseWriter, _ *http.Request) { + runtime.GC() + fmt.Fprintf(w, "GC run complete") + }) + + s := http.Server{Addr: l.Addr().String(), ReadHeaderTimeout: 3 * time.Second, Handler: mux} + go func() { + logger.Warnw("", "metrics", "listen finished", "err", s.Serve(l)) + }() + return l +} + +// remotePeerHandler is a structure that handles all peers that +// this node is connected to regardless of which group they are a part of. +type remotePeerHandler struct { + log log.Logger + client Client +} + +// newRemotePeerHandler creates a new remotePeerHandler from a MetricsClient +func newRemotePeerHandler(logger log.Logger, cli Client) *remotePeerHandler { + return &remotePeerHandler{ + log: logger, + client: cli, + } +} + +// ServeHTTP serves the metrics for the peer whose address is given in the URI. +// It assumes that the URI is in the form /peer/ +func (l *remotePeerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + addr := strings.Replace(r.URL.Path, "/peer/", "", 1) + if index := strings.Index(addr, "/"); index != -1 { + addr = addr[:index] + } + + metrics, err := l.client.GetMetrics(r.Context(), addr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + } + + l.log.Debugw("Received metrics through GRPC", "from", addr, "err", err) + + _, err = w.Write([]byte(metrics)) + if err != nil { + l.log.Errorw("Error serving remote metrics for peer", "addr", addr) + } +} + +func getBuildTimestamp(buildDate string) int64 { + if buildDate == "" { + return 0 + } + + layout := "02/01/2006@15:04:05" + t, err := time.Parse(layout, buildDate) + if err != nil { + return 0 + } + return t.Unix() +} + +// DKGStateChange emits appropriate dkgState, dkgStateTimestamp and dkgLeader metrics +func DKGStateChange(beaconID string, epoch uint32, leader bool, state uint32) { + leading := 0.0 + if leader { + leading = 1.0 + } + dkgEpoch.WithLabelValues(beaconID).Set(float64(epoch)) + dkgState.WithLabelValues(beaconID).Set(float64(state)) + dkgStateTimestamp.WithLabelValues(beaconID).SetToCurrentTime() + dkgLeader.WithLabelValues(beaconID).Set(leading) +} + +func ErrorSendingPartial(beaconID, address string) { + ErrorSendingPartialCounter.WithLabelValues(beaconID, address).Set(1) +} + +func SuccessfulPartial(beaconID, address string) { + ErrorSendingPartialCounter.WithLabelValues(beaconID, address).Set(0) +} diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go new file mode 100644 index 0000000..44092a6 --- /dev/null +++ b/internal/metrics/metrics_test.go @@ -0,0 +1,23 @@ +package metrics + +import ( + "testing" + "time" +) + +// Note that the remote peer metrics are tested in TestMetricsForPeer in cli_test.go + +func TestBuildTimestamp(t *testing.T) { + buildTimestamp := "29/04/2021@20:23:35" + + reference, err := time.Parse(time.RFC3339, "2021-04-29T20:23:35Z") + if err != nil { + t.Fatalf("Error parsing reference time: %s", err) + } + expected := reference.Unix() + + actual := getBuildTimestamp(buildTimestamp) + if actual != expected { + t.Fatalf("Error converting build timestamp to number. Expected %v, actual %v", expected, actual) + } +} diff --git a/internal/metrics/pprof/pprof.go b/internal/metrics/pprof/pprof.go new file mode 100644 index 0000000..31b7ae6 --- /dev/null +++ b/internal/metrics/pprof/pprof.go @@ -0,0 +1,23 @@ +// Package pprof is separated out from metrics to isolate the 'init' functionality of pprof, so that it is +// included when used by binaries, but not if other drand packages get used or integrated into clients that +// don't expect the pprof side effect to have taken effect. +package pprof + +import ( + "net/http" + "net/http/pprof" // adds default pprof endpoint at /debug/pprof +) + +// WithProfile provides an http mux setup to serve pprof endpoints. it should be mounted at /debug/pprof +func WithProfile() http.Handler { + mux := http.NewServeMux() + + mux.HandleFunc("/", pprof.Index) + // sub-path need to handle the whole path for the matching to work + mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + + return mux +} From a7ef367e918601ba477bd15fcfbf0af98db4e5f7 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Mon, 15 Jul 2024 23:44:02 +0200 Subject: [PATCH 22/28] some progress --- .golangci.yml | 5 +- client/client.go | 8 ++ client/client_test.go | 10 +- client/doc.go | 2 +- client/http/http.go | 6 + client/http/http_test.go | 10 +- client/lp2p/client.go | 5 +- client/lp2p/client_test.go | 211 +++++++++++++++------------- client/mock/mock.go | 2 + client/random.go | 9 +- client/test/http/mock/httpserver.go | 4 +- client/verify.go | 2 +- go.mod | 5 +- go.sum | 6 + internal/cli.go | 39 +++-- internal/cli_test.go | 6 +- internal/grpc/client.go | 12 +- internal/lib/cli.go | 37 ++++- internal/lib/cli_test.go | 6 +- 19 files changed, 225 insertions(+), 160 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 60fa1d0..7e166cb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -33,6 +33,7 @@ issues: run: skip-dirs: - demo + - test linters: enable: @@ -59,7 +60,7 @@ linters: # - exhaustivestruct # - exhaustruct - exportloopref - - forbidigo + # - forbidigo # - forcetypeassert #TODO could be enabled - funlen # - gci @@ -96,7 +97,7 @@ linters: - maintidx - makezero # - maligned #Deprecated - - mnd + #- mnd - misspell - nakedret # - nestif diff --git a/client/client.go b/client/client.go index 6cc8d4e..8e37187 100644 --- a/client/client.go +++ b/client/client.go @@ -319,3 +319,11 @@ func WithAutoWatchRetry(interval time.Duration) Option { return nil } } + +// WithPrometheus specifies a registry into which to report metrics +func WithPrometheus(r prometheus.Registerer) Option { + return func(cfg *clientConfig) error { + cfg.prometheus = r + return nil + } +} diff --git a/client/client_test.go b/client/client_test.go index 1c05e03..5152dda 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -53,10 +53,10 @@ func TestClientMultiple(t *testing.T) { require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - addr2, chaininfo2, cancel2 := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr2, chaininfo2, cancel2, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel2() t.Log("created mockhttppublicserver", "addr", addr1, "chaininfo", chainInfo) @@ -116,7 +116,7 @@ func TestClientCache(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() lg := log.New(nil, log.DebugLevel, true) @@ -156,7 +156,7 @@ func TestClientWithoutCache(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() lg := log.New(nil, log.DebugLevel, true) @@ -289,7 +289,7 @@ func TestClientAutoWatch(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr1, chainInfo, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr1, chainInfo, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() httpClient := http.ForURLs(ctx, lg, []string{"http://" + addr1}, chainInfo.Hash()) diff --git a/client/doc.go b/client/doc.go index eb4bf9c..c4a5fca 100644 --- a/client/doc.go +++ b/client/doc.go @@ -34,7 +34,7 @@ Example: } The "From" option allows you to specify clients that work over particular -transports. HTTP, gRPC and libp2p PubSub clients are provided in drand's +transports. HTTP, gRPC and libp2p PubSub clients are provided as subpackages https://pkg.go.dev/github.com/drand/drand-cli/internal/client/http, https://pkg.go.dev/github.com/drand/drand-cli/internal/client/grpc and https://pkg.go.dev/github.com/drand/drand-cli/internal/lp2p/clientlp2p/client diff --git a/client/http/http.go b/client/http/http.go index 1f0403d..e7e767e 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -12,6 +12,7 @@ import ( "time" client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand/v2/crypto" json "github.com/nikkolasg/hexjson" @@ -21,6 +22,8 @@ import ( "github.com/drand/drand/v2/common/log" ) +var _ client.Client = &httpClient{} + var errClientClosed = fmt.Errorf("client closed") const defaultClientExec = "unknown" @@ -258,6 +261,7 @@ func (h *httpClient) FetchChainInfo(ctx context.Context, chainHash []byte) (*cha resC <- httpInfoResponse{nil, err} return } + resC <- httpInfoResponse{chainInfo, nil} }() @@ -316,6 +320,8 @@ func (h *httpClient) Get(ctx context.Context, round uint64) (client.Result, erro return } + randResp.Random = crypto.RandomnessFromSignature(randResp.GetSignature()) + resC <- httpGetResponse{&randResp, nil} }() diff --git a/client/http/http_test.go b/client/http/http_test.go index b38e7a0..d168462 100644 --- a/client/http/http_test.go +++ b/client/http/http_test.go @@ -23,7 +23,7 @@ func TestHTTPClient(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, true, sch, clk) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, true, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -67,7 +67,7 @@ func TestHTTPGetLatest(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -106,7 +106,7 @@ func TestForURLsCreation(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -132,7 +132,7 @@ func TestHTTPWatch(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) @@ -167,7 +167,7 @@ func TestHTTPClientClose(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, chainInfo, cancel := mock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, chainInfo, cancel, _ := mock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() err = IsServerReady(ctx, addr) diff --git a/client/lp2p/client.go b/client/lp2p/client.go index a9ac833..346fddf 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -156,7 +156,7 @@ func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache clie // UnsubFunc is a cancel function for pubsub subscription type UnsubFunc func() -// Sub subscribes to notfications about new randomness. +// Sub subscribes to notifications about new randomness. // Client instance owns the channel after it is passed to Sub function, // thus the channel should not be closed by library user // @@ -217,9 +217,6 @@ func (c *Client) Watch(ctx context.Context) <-chan client.Result { case <-ctx.Done(): c.log.Debugw("client.Watch done") end() - // drain leftover on innerCh - for range innerCh { - } c.log.Debugw("client.Watch finished draining the innerCh") return } diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index d055da1..8968f30 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -1,15 +1,29 @@ package lp2p import ( + "context" "fmt" + "net/http" + "path" + "strconv" "testing" "time" + "github.com/hashicorp/consul/sdk/freeport" + bds "github.com/ipfs/go-ds-badger2" + clock "github.com/jonboulle/clockwork" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" + dhttp "github.com/drand/drand-cli/client/http" + httpmock "github.com/drand/drand-cli/client/test/http/mock" + "github.com/drand/drand-cli/internal/lp2p" + chain2 "github.com/drand/drand/v2/common/chain" "github.com/drand/drand/v2/common/client" + "github.com/drand/drand/v2/common/log" + "github.com/drand/drand/v2/crypto" ) // @@ -105,108 +119,103 @@ func drain(t *testing.T, ch <-chan client.Result, timeout time.Duration) { } } -// -// func TestHTTPClientTestFunc(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping slow test in short mode.") -// } -// -// ctx := context.Background() -// lg := log.New(nil, log.DebugLevel, true) -// sch, err := crypto.GetSchemeFromEnv() -// require.NoError(t, err) -// -// clk := clock.NewFakeClockAt(time.Now()) -// -// addr, chainInfo, stop, emit := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) -// defer stop() -// -// dataDir := t.TempDir() -// identityDir := t.TempDir() -// -// httpClient, err := dhttp.New(ctx, lg, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) -// require.NoError(t, err) -// -// cfg := &lp2p.GossipRelayConfig{ -// ChainHash: chainInfo.HashString(), -// PeerWith: nil, -// Addr: "/ip4/127.0.0.1/tcp/" + test.FreePort(), -// DataDir: dataDir, -// IdentityPath: path.Join(identityDir, "identity.key"), -// Client: httpClient, -// } -// g, err := lp2p.NewGossipRelayNode(lg, cfg) -// if err != nil { -// t.Fatalf("gossip relay node (%v)", err) -// } -// defer g.Shutdown() -// -// c, err := newTestClient(t, g.Multiaddrs(), chainInfo, clk) -// if err != nil { -// t.Fatal(err) -// } -// defer c.Close() -// -// ctx, cancel := context.WithCancel(ctx) -// emit(false) -// ch := c.Watch(ctx) -// for i := 0; i < 3; i++ { -// // pub sub polls every 200ms, but the other http one polls every period -// time.Sleep(1250 * time.Millisecond) -// emit(false) -// select { -// case r, ok := <-ch: -// if !ok { -// t.Fatal("expected randomness") -// } else { -// t.Log("received randomness", r.GetRound()) -// } -// case <-time.After(8 * time.Second): -// t.Fatal("timeout.") -// } -// } -// emit(true) -// cancel() -// drain(t, ch, 5*time.Second) -//} +func TestHTTPClientTestFunc(t *testing.T) { + ctx := context.Background() + lg := log.New(nil, log.DebugLevel, true) + sch, err := crypto.GetSchemeFromEnv() + require.NoError(t, err) -// func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { -// dataDir := t.TempDir() -// identityDir := t.TempDir() -// ds, err := bds.NewDatastore(dataDir, nil) -// if err != nil { -// return nil, err -// } -// lg := log.New(nil, log.DebugLevel, true) -// priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) -// if err != nil { -// return nil, err -// } -// h, ps, err := lp2p.ConstructHost( -// ds, -// priv, -// "/ip4/0.0.0.0/tcp/"+test.FreePort(), -// relayMultiaddr, -// lg, -// ) -// if err != nil { -// return nil, err -// } -// relayPeerID, err := peerIDFromMultiaddr(relayMultiaddr[0]) -// if err != nil { -// return nil, err -// } -// err = waitForConnection(h, relayPeerID, time.Minute) -// if err != nil { -// return nil, err -// } -// c, err := NewWithPubsub(lg, ps, info, nil, clk, 100) -// if err != nil { -// return nil, err -// } -// c.SetLog(lg) -// return c, nil -//} + clk := clock.NewFakeClockAt(time.Now()) + + addr, chainInfo, stop, emit := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + defer stop() + + dataDir := t.TempDir() + identityDir := t.TempDir() + + httpClient, err := dhttp.New(ctx, lg, "http://"+addr, chainInfo.Hash(), http.DefaultTransport) + require.NoError(t, err) + + cfg := &lp2p.GossipRelayConfig{ + ChainHash: chainInfo.HashString(), + PeerWith: nil, + Addr: "/ip4/127.0.0.1/tcp/" + strconv.Itoa(freeport.GetOne(t)), + DataDir: dataDir, + IdentityPath: path.Join(identityDir, "identity.key"), + Client: httpClient, + } + g, err := lp2p.NewGossipRelayNode(lg, cfg) + if err != nil { + t.Fatalf("gossip relay node (%v)", err) + } + defer g.Shutdown() + + c, err := newTestClient(t, g.Multiaddrs(), chainInfo, clk) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + ctx, cancel := context.WithCancel(ctx) + emit(false) + ch := c.Watch(ctx) + for i := 0; i < 3; i++ { + // pub sub polls every 200ms, but the other http one polls every period + time.Sleep(1250 * time.Millisecond) + emit(false) + select { + case r, ok := <-ch: + if !ok { + t.Fatal("expected randomness") + } else { + t.Log("received randomness", r.GetRound()) + } + case <-time.After(8 * time.Second): + t.Fatal("timeout.") + } + } + emit(true) + cancel() + drain(t, ch, 5*time.Second) +} + +func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { + dataDir := t.TempDir() + identityDir := t.TempDir() + ds, err := bds.NewDatastore(dataDir, nil) + if err != nil { + return nil, err + } + lg := log.New(nil, log.DebugLevel, true) + priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) + if err != nil { + return nil, err + } + h, ps, err := lp2p.ConstructHost( + ds, + priv, + "/ip4/0.0.0.0/tcp/"+strconv.Itoa(freeport.GetOne(t)), + relayMultiaddr, + lg, + ) + if err != nil { + return nil, err + } + relayPeerID, err := peerIDFromMultiaddr(relayMultiaddr[0]) + if err != nil { + return nil, err + } + err = waitForConnection(h, relayPeerID, time.Minute) + if err != nil { + return nil, err + } + c, err := NewWithPubsub(lg, ps, info, nil, clk, 100) + if err != nil { + return nil, err + } + c.SetLog(lg) + return c, nil +} func peerIDFromMultiaddr(addr ma.Multiaddr) (peer.ID, error) { ai, err := peer.AddrInfoFromP2pAddr(addr) diff --git a/client/mock/mock.go b/client/mock/mock.go index d1225f1..26ea8ea 100644 --- a/client/mock/mock.go +++ b/client/mock/mock.go @@ -12,6 +12,8 @@ import ( "github.com/drand/drand/v2/common/client" ) +var _ client.Client = &Client{} + // Client provide a mocked client interface // //nolint:gocritic diff --git a/client/random.go b/client/random.go index e1d0d47..707e399 100644 --- a/client/random.go +++ b/client/random.go @@ -1,5 +1,9 @@ package client +import ( + "github.com/drand/drand/v2/crypto" +) + // RandomData holds the full random response from the server, including data needed // for validation. type RandomData struct { @@ -27,5 +31,8 @@ func (r *RandomData) GetPreviousSignature() []byte { // GetRandomness exports the randomness using the legacy SHA256 derivation path func (r *RandomData) GetRandomness() []byte { - return r.Random + if r.Random != nil { + return r.Random + } + return crypto.RandomnessFromSignature(r.GetSignature()) } diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index ce8b124..c2618b7 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -23,7 +23,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 NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Scheme, clk clock.Clock) (string, *chain.Info, context.CancelFunc, func(bool)) { t.Helper() server := mock.NewMockServer(t, badSecondRound, sch, clk) @@ -67,7 +67,7 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche return listener.Addr().String(), chainInfo, func() { httpServer.Shutdown(context.Background()) cancel() - } + }, server.(mock.Service).EmitRand } // drandProxy is used as a proxy between a Public service (e.g. the node as a server) diff --git a/client/verify.go b/client/verify.go index 304a0b1..9af97fd 100644 --- a/client/verify.go +++ b/client/verify.go @@ -102,7 +102,7 @@ func asRandomData(r client.Result) *RandomData { } rd = &RandomData{ Rnd: r.GetRound(), - Random: r.GetRandomness(), + Random: crypto.RandomnessFromSignature(r.GetSignature()), Sig: r.GetSignature(), } if rp, ok := r.(resultWithPreviousSignature); ok { diff --git a/go.mod b/go.mod index ebf23ee..44e084e 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect @@ -63,6 +63,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/hashicorp/consul/sdk v0.16.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -121,7 +122,7 @@ require ( github.com/pion/transport/v2 v2.2.5 // indirect github.com/pion/turn/v2 v2.1.6 // indirect github.com/pion/webrtc/v3 v3.2.44 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/go.sum b/go.sum index 4afadf4..267aba6 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= @@ -183,6 +185,8 @@ 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/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= +github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -401,6 +405,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= diff --git a/internal/cli.go b/internal/cli.go index 5a61345..f059d4c 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -3,9 +3,10 @@ package drand import ( "fmt" "log" - "os" + "strconv" "sync" + json "github.com/nikkolasg/hexjson" "github.com/urfave/cli/v2" client "github.com/drand/drand/v2/common/client" @@ -23,12 +24,6 @@ var ( var SetVersionPrinter sync.Once -var verboseFlag = &cli.BoolFlag{ - Name: "verbose", - Usage: "If set, verbosity is at the debug level", - EnvVars: []string{"DRAND_VERBOSE"}, -} - var appCommands = []*cli.Command{ { Name: "get", @@ -40,7 +35,7 @@ var appCommands = []*cli.Command{ Usage: "Get the latest public randomness from the drand " + "relay and verify it against the collective public key " + "as specified in the chain-info.\n", - Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag), + Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag, lib.VerboseFlag), ArgsUsage: "--url url1 --url url2 ROUND... uses the first working relay to query round number ROUND", Action: getPublicRandomness, }, @@ -48,7 +43,7 @@ var appCommands = []*cli.Command{ Name: "chain-info", Usage: "Get beacon information", ArgsUsage: "--url url1 --url url2 ... uses the first working relay", - Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag), + Flags: toArray(lib.URLFlag, lib.JSONFlag, lib.InsecureFlag, lib.HashListFlag, lib.VerboseFlag), Action: getChainInfo, }, }, @@ -71,7 +66,7 @@ func CLI() *cli.App { } }) - app.ExitErrHandler = func(context *cli.Context, err error) { + app.ExitErrHandler = func(_ *cli.Context, _ error) { // override to prevent default behavior of calling OS.exit(1), // when tests expect to be able to run multiple commands. } @@ -88,14 +83,8 @@ func CLI() *cli.App { appComm[i] = &v } app.Commands = appComm - // we need to copy the underlying flags to avoid races - verbFlag := *verboseFlag - app.Flags = toArray(&verbFlag) - return app -} -func isVerbose(c *cli.Context) bool { - return c.IsSet(verboseFlag.Name) + return app } func toArray(flags ...cli.Flag) []cli.Flag { @@ -121,15 +110,23 @@ func getPublicRandomness(cctx *cli.Context) error { if err != nil { return err } - if len(os.Args) > 1 { + if cctx.Args().Len() > 1 { log.Fatal("please specify a single round as positional argument") } - round, err := c.Get(cctx.Context, 0) + var r uint64 + if val := cctx.Args().Get(0); val != "" { + r, err = strconv.ParseUint(val, 10, 64) + if err != nil { + return err + } + } + + round, err := c.Get(cctx.Context, r) if err != nil { return err } - fmt.Println(round) + json.NewEncoder(cctx.App.Writer).Encode(round) return nil } @@ -142,6 +139,6 @@ func getChainInfo(cctx *cli.Context) error { if err != nil { return err } - fmt.Println(info) + info.ToJSON(cctx.App.Writer, nil) return nil } diff --git a/internal/cli_test.go b/internal/cli_test.go index 2315ea5..6625422 100644 --- a/internal/cli_test.go +++ b/internal/cli_test.go @@ -12,11 +12,11 @@ func TestClientTLS(t *testing.T) { addr := "https://api.drand.sh" chainInfoCmd := []string{"drand", "get", "chain-info", "--url", addr, "--insecure"} - expectedInOutput := "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce" + expectedInOutput := "868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31" testCommand(t, chainInfoCmd, expectedInOutput) - showHash := []string{"drand", "get", "public", "--url", addr, "--insecure"} - round1 := "101297f1ca7dc44ef6088d94ad5fb7ba03455dc33d53ddb412bbc4564ed986ec" + showHash := []string{"drand", "get", "public", "--url", addr, "--insecure", "123"} + round1 := "0e4f538534f426203a4089154ff31527b9c25b37f9d6704b3ecba8d74678b4e3" testCommand(t, showHash, round1) } diff --git a/internal/grpc/client.go b/internal/grpc/client.go index 47396f5..7b30b26 100644 --- a/internal/grpc/client.go +++ b/internal/grpc/client.go @@ -12,6 +12,8 @@ import ( "google.golang.org/grpc/credentials" grpcInsec "google.golang.org/grpc/credentials/insecure" + "github.com/drand/drand/v2/crypto" + localClient "github.com/drand/drand-cli/client" commonutils "github.com/drand/drand/v2/common" "github.com/drand/drand/v2/common/chain" @@ -42,7 +44,7 @@ func New(address string, insecure bool, chainHash []byte) (client.Client, error) grpc.WithUnaryInterceptor(grpcProm.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpcProm.StreamClientInterceptor), ) - conn, err := grpc.Dial(address, opts...) + conn, err := grpc.NewClient(address, opts...) if err != nil { return nil, err } @@ -52,10 +54,10 @@ func New(address string, insecure bool, chainHash []byte) (client.Client, error) func asRD(r *drand.PublicRandResponse) *localClient.RandomData { return &localClient.RandomData{ - Rnd: r.Round, - Random: r.Randomness, - Sig: r.Signature, - PreviousSignature: r.PreviousSignature, + Rnd: r.GetRound(), + Random: crypto.RandomnessFromSignature(r.GetSignature()), + Sig: r.GetSignature(), + PreviousSignature: r.GetPreviousSignature(), } } diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 459511d..5993a39 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -3,6 +3,7 @@ package lib import ( "bytes" "encoding/hex" + "errors" "fmt" "net" nhttp "net/http" @@ -91,6 +92,12 @@ var ( Name: "json", Usage: "Set the output as json format", } + + VerboseFlag = &cli.BoolFlag{ + Name: "verbose", + Usage: "If set, verbosity is at the debug level", + EnvVars: []string{"DRAND_VERBOSE"}, + } ) // ClientFlags is a list of common flags for client creation @@ -103,6 +110,7 @@ var ClientFlags = []cli.Flag{ InsecureFlag, RelayFlag, JSONFlag, + VerboseFlag, } // Create builds a client, and can be invoked from a cli action supplied @@ -110,7 +118,13 @@ var ClientFlags = []cli.Flag{ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) (client.Client, error) { ctx := c.Context clients := make([]client.Client, 0) - l := log.New(nil, log.DebugLevel, false) + var level int + if c.Bool(VerboseFlag.Name) { + level = log.DebugLevel + } else { + level = log.WarnLevel + } + l := log.New(nil, level, false) var info *chainCommon.Info var err error @@ -167,6 +181,15 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) if len(gc) > 0 { clients = append(clients, gc...) } + if info != nil && hash != nil && !bytes.Equal(hash, info.Hash()) { + return nil, fmt.Errorf( + "%w for beacon %s : expected %v != info %v", + commonutils.ErrInvalidChainHash, + info.ID, + hex.EncodeToString(hash), + hex.EncodeToString(info.Hash()), + ) + } gopt, err := buildGossipClient(c, l) if err != nil { @@ -237,7 +260,16 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta clients = append(clients, hc) } + if len(skipped) == len(c.StringSlice(URLFlag.Name)) { + return nil, nil, errors.New("all URLs failed to be used for creating a http client") + } + if info != nil { + if hash != nil && !bytes.Equal(hash, info.Hash()) { + l.Warnw("mismatch between retrieved chain info hash and provided hash", "chainInfo", info.Hash(), "provided", hash) + return nil, nil, errors.New("mismatch between retrieved chain info and provided hash") + } + for _, url := range skipped { hc, err = http2.NewWithInfo(l, url, info, nhttp.DefaultTransport) if err != nil { @@ -246,9 +278,6 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta } clients = append(clients, hc) } - if !bytes.Equal(hash, info.Hash()) { - l.Warnw("mismatch between retrieved chain info hash and provided hash", "chainInfo", info.Hash(), "provided", hash) - } } if withInstrumentation { diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index 58089c1..cd4f022 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -61,7 +61,7 @@ func TestClientLib(t *testing.T) { sch, err := crypto.GetSchemeFromEnv() require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, info, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) @@ -71,7 +71,7 @@ func TestClientLib(t *testing.T) { args := []string{"mock-client", "--url", "http://" + addr, "--insecure"} err = run(lg, args) if err != nil { - t.Fatal("HTTP should work", err) + t.Fatal("HTTP should work. err:", err) } args = []string{"mock-client", "--url", "https://" + addr} @@ -119,7 +119,7 @@ func TestClientLibGroupConfJSON(t *testing.T) { require.NoError(t, err) clk := clock.NewFakeClockAt(time.Now()) - addr, info, cancel := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) + addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() var b bytes.Buffer From a4b0eadb558fca3886152bf8184e6ff806850f64 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Mon, 22 Jul 2024 22:37:15 +0200 Subject: [PATCH 23/28] Baby steps on client code --- README.md | 8 +++- client/http/example_test.go | 46 ++++++++++++++++++++++ client/http/http.go | 7 +++- client/lp2p/client.go | 56 +++++++++++++++++++------- client/lp2p/example_test.go | 78 +++++++++++++++++++++++++++++++++++++ client/lp2p/validator.go | 11 +++--- client/verify.go | 1 + internal/cli.go | 5 ++- internal/lib/cli.go | 2 + internal/lib/cli_test.go | 2 + 10 files changed, 190 insertions(+), 26 deletions(-) create mode 100644 client/http/example_test.go create mode 100644 client/lp2p/example_test.go diff --git a/README.md b/README.md index f3a4c45..6d39907 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ -## New Project +## drand-cli is a set of useful binaries for the drand ecosystem + +This repo contains most notably: + - a client CLI tool to fetch and verify drand beacons from the various available sources + - a gossipsub relay to relay drand beacons on gossipsub + - Go APIs to connect to drand networks through http or gossipsub relays. + --- diff --git a/client/http/example_test.go b/client/http/example_test.go new file mode 100644 index 0000000..ad7857e --- /dev/null +++ b/client/http/example_test.go @@ -0,0 +1,46 @@ +package http_test + +import ( + "context" + "encoding/hex" + "fmt" + + client2 "github.com/drand/drand-cli/client" + "github.com/drand/drand-cli/client/http" + "github.com/drand/drand/v2/crypto" +) + +func ExampleHttpNew() { + chainhash, err := hex.DecodeString("52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971") + client, err := http.New(context.Background(), nil, "http://api.drand.sh", chainhash, nil) + if err != nil { + panic(err) + } + + result, err := client.Get(context.Background(), 1234) + if err != nil { + panic(err) + } + + info, err := client.Info(context.Background()) + if err != nil { + panic(err) + } + + scheme, err := crypto.SchemeFromName(info.GetSchemeName()) + if err != nil { + panic(err) + } + + // make sure to verify the beacons when using the raw http client without a verifying client + err = scheme.VerifyBeacon(&client2.RandomData{ + Rnd: result.GetRound(), + Sig: result.GetSignature(), + }, info.PublicKey) + if err != nil { + panic(err) + } + + fmt.Printf("got beacon: round=%d; randomness=%x\n", result.GetRound(), result.GetRandomness()) + //output: got beacon: round=1234; randomness=9ead58abb451d8f521338c43ba5595610642a0c07d0e9babeaae6a98787629de +} diff --git a/client/http/http.go b/client/http/http.go index e7e767e..d3cbd19 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -34,7 +34,10 @@ const httpWaitInterval = 2 * time.Second const maxTimeoutHTTPRequest = 5 * time.Second // New creates a new client pointing to an HTTP endpoint -func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transport nhttp.RoundTripper) (client.Client, error) { +func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transport nhttp.RoundTripper) (*httpClient, error) { + if l == nil { + l = log.DefaultLogger() + } if transport == nil { transport = nhttp.DefaultTransport } @@ -64,7 +67,7 @@ func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transp } // NewWithInfo constructs an http client when the group parameters are already known. -func NewWithInfo(l log.Logger, url string, info *chain2.Info, transport nhttp.RoundTripper) (client.Client, error) { +func NewWithInfo(l log.Logger, url string, info *chain2.Info, transport nhttp.RoundTripper) (*httpClient, error) { if transport == nil { transport = nhttp.DefaultTransport } diff --git a/client/lp2p/client.go b/client/lp2p/client.go index 346fddf..ecd1230 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -9,8 +9,10 @@ import ( clock "github.com/jonboulle/clockwork" "github.com/libp2p/go-libp2p" pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" + dnsaddr "github.com/multiformats/go-multiaddr-dns" "google.golang.org/protobuf/proto" client2 "github.com/drand/drand-cli/client" @@ -61,14 +63,26 @@ func PubSubTopic(h string) string { return fmt.Sprintf("/drand/pubsub/v0.0.0/%s", h) } -// NewWithPubsub creates a gossip randomness client. +// NewWithPubsub creates a gossip randomness client. If the logger l is nil, it will default to +// a default Logger, // -//nolint:funlen,lll // This is the correct function length +//nolint:funlen,lll // This is a long line func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache client2.Cache, clk clock.Clock, bufferSize int) (*Client, error) { if info == nil { return nil, fmt.Errorf("no chain supplied for joining") } + if l == nil { + l = log.DefaultLogger() + } + + scheme, err := crypto.SchemeFromName(info.Scheme) + if err != nil { + l.Errorw("invalid scheme in info", "info", info, "scheme", info.Scheme, "err", err) + + return nil, fmt.Errorf("invalid scheme in info: %w", err) + } + ctx, cancel := context.WithCancel(context.Background()) c := &Client{ cancel: cancel, @@ -128,7 +142,11 @@ func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache clie continue } - // TODO: verification, need to pass drand network public key in + err = scheme.VerifyBeacon(&rand, info.PublicKey) + if err != nil { + c.log.Errorw("invalid signature for beacon", "round", rand.GetRound(), "err", err) + continue + } if c.latest >= rand.Round { c.log.Debugw("received round older than the latest previously received one", "latest", c.latest, "round", rand.Round) @@ -235,22 +253,30 @@ func (c *Client) Close() error { } // NewPubsub constructs a basic libp2p pubsub module for use with the drand client. -func NewPubsub(ctx context.Context, listenAddr, relayAddr string) (*pubsub.PubSub, error) { +// The local libp2p host is returned as well to allow to properly close it once done. +func NewPubsub(ctx context.Context, listenAddr string, relayAddrs []string) (*pubsub.PubSub, host.Host, error) { h, err := libp2p.New(libp2p.ListenAddrStrings(listenAddr)) if err != nil { - return nil, err + return nil, nil, err } - relayMa, err := multiaddr.NewMultiaddr(relayAddr) - if err != nil { - return nil, err - } - - relayAi, err := peer.AddrInfoFromP2pAddr(relayMa) - if err != nil { - return nil, err + peers := make([]peer.AddrInfo, 0, len(relayAddrs)) + for _, relayAddr := range relayAddrs { + // resolve the relay multiaddr to peers' AddrInfo + mas, err := dnsaddr.Resolve(ctx, multiaddr.StringCast(relayAddr)) + if err != nil { + return nil, nil, fmt.Errorf("dnsaddr.Resolve error: %w", err) + } + for _, ma := range mas { + relayAi, err := peer.AddrInfoFromP2pAddr(ma) + if err != nil { + h.Close() + return nil, nil, fmt.Errorf("peer.AddrInfoFromP2pAddr error: %w", err) + } + peers = append(peers, *relayAi) + } } - dps := []peer.AddrInfo{*relayAi} - return pubsub.NewGossipSub(ctx, h, pubsub.WithDirectPeers(dps)) + ps, err := pubsub.NewGossipSub(ctx, h, pubsub.WithDirectPeers(peers)) + return ps, h, err } diff --git a/client/lp2p/example_test.go b/client/lp2p/example_test.go new file mode 100644 index 0000000..0d7d7e3 --- /dev/null +++ b/client/lp2p/example_test.go @@ -0,0 +1,78 @@ +package lp2p_test + +import ( + "bytes" + "context" + "fmt" + "time" + + gclient "github.com/drand/drand-cli/client/lp2p" + "github.com/drand/drand/v2/common" + "github.com/drand/drand/v2/common/chain" + "github.com/drand/drand/v2/common/log" + clock "github.com/jonboulle/clockwork" +) + +const ( + // relayP2PAddr is the p2p multiaddr of the drand gossipsub relay node to connect to. + relayP2PAddr = "/dnsaddr/api.drand.sh" + relayP2PAddr2 = "/dnsaddr/api2.drand.sh" + relayP2PAddr3 = "/dnsaddr/api3.drand.sh" + + jsonDefaultInfo = `{ + "genesis_time": 1595431050, + "groupHash": "176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a", + "hash": "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce", + "metadata": { + "beaconID": "default" + }, + "period": 30, + "public_key": "868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31", + "schemeID": "pedersen-bls-chained" +}` + // jsonQuicknetInfo, can be hardcoded since these don't change over time + jsonQuicknetInfo = `{ + "genesis_time": 1692803367, + "groupHash": "f477d5c89f21a17c863a7f937c6a6d15859414d2be09cd448d4279af331c5d3e", + "hash": "52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971", + "metadata": { + "beaconID": "quicknet" + }, + "period": 3, + "public_key": "83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a", + "schemeID": "bls-unchained-g1-rfc9380" +} +` +) + +func ExampleNewPubsub() { + ctx := context.Background() + + // /0 to use a random free port + ps, h, err := gclient.NewPubsub(ctx, "/ip4/0.0.0.0/tcp/0", []string{relayP2PAddr, relayP2PAddr2, relayP2PAddr3}) + if err != nil { + panic(err) + } + defer h.Close() + + info, err := chain.InfoFromJSON(bytes.NewReader([]byte(jsonQuicknetInfo))) + if err != nil { + panic(err) + } + + // NewWithPubSub will automatically register the topic for the chainhash you're interested in + c, err := gclient.NewWithPubsub(log.DefaultLogger(), ps, info, nil, clock.NewRealClock(), gclient.DefaultBufferSize) + if err != nil { + panic(err) + } + + // This can be slow to "start" + for res := range c.Watch(context.Background()) { + expected := common.CurrentRound(time.Now().Unix(), info.Period, info.GenesisTime) + fmt.Println("correct round:", expected == res.GetRound(), "with", len(res.GetRandomness()), "random bytes") + // we just waited on the first one as an example + break + } + + //output: correct round: true with 32 random bytes +} diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go index e0ce892..c88a2c9 100644 --- a/client/lp2p/validator.go +++ b/client/lp2p/validator.go @@ -19,6 +19,10 @@ import ( ) func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk clock.Clock) pubsub.ValidatorEx { + var scheme *crypto.Scheme + if info != nil { + scheme, _ = crypto.GetSchemeByID(info.Scheme) + } return func(ctx context.Context, p peer.ID, m *pubsub.Message) pubsub.ValidationResult { rand := &drand.PublicRandResponse{} err := proto.Unmarshal(m.Data, rand) @@ -65,7 +69,7 @@ func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk c return pubsub.ValidationReject } if current.GetRound() == rand.GetRound() && - bytes.Equal(current.GetRandomness(), rand.GetRandomness()) && + bytes.Equal(current.GetRandomness(), crypto.RandomnessFromSignature(rand.GetSignature())) && bytes.Equal(current.GetSignature(), rand.GetSignature()) && bytes.Equal(currentFull.PreviousSignature, rand.GetPreviousSignature()) { c.log.Warnw("", "gossip validator", "ignore") @@ -75,11 +79,6 @@ func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk c return pubsub.ValidationReject } } - scheme, err := crypto.SchemeFromName(info.Scheme) - if err != nil { - c.log.Warnw("", "gossip validator", "reject", "err", err) - return pubsub.ValidationReject - } err = scheme.VerifyBeacon(rand, info.PublicKey) if err != nil { diff --git a/client/verify.go b/client/verify.go index 9af97fd..d550deb 100644 --- a/client/verify.go +++ b/client/verify.go @@ -98,6 +98,7 @@ type resultWithPreviousSignature interface { func asRandomData(r client.Result) *RandomData { rd, ok := r.(*RandomData) if ok { + rd.Random = crypto.RandomnessFromSignature(rd.GetSignature()) return rd } rd = &RandomData{ diff --git a/internal/cli.go b/internal/cli.go index f059d4c..181f9f6 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -135,10 +135,11 @@ func getChainInfo(cctx *cli.Context) error { if err != nil { return err } + info, err := c.Info(cctx.Context) if err != nil { return err } - info.ToJSON(cctx.App.Writer, nil) - return nil + + return info.ToJSON(cctx.App.Writer, nil) } diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 5993a39..5af2569 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -115,6 +115,8 @@ var ClientFlags = []cli.Flag{ // Create builds a client, and can be invoked from a cli action supplied // with ClientFlags +// +//nolint:gocyclo func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) (client.Client, error) { ctx := c.Context clients := make([]client.Client, 0) diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index cd4f022..e2bfdbe 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -64,6 +64,8 @@ func TestClientLib(t *testing.T) { addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() + time.Sleep(time.Second) + grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) go grpcLis.Start() defer grpcLis.Stop(context.Background()) From bef8466e7b91ebc3b4f2bc477496e86dcd3d8b69 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 23 Jul 2024 15:11:09 +0200 Subject: [PATCH 24/28] removing hardcoded non-executed example code from doc now examples are provided using the Go test framework in the example_test.go files --- client/lp2p/doc.go | 81 +--------------------------------------------- 1 file changed, 1 insertion(+), 80 deletions(-) diff --git a/client/lp2p/doc.go b/client/lp2p/doc.go index 140505f..3889740 100644 --- a/client/lp2p/doc.go +++ b/client/lp2p/doc.go @@ -6,91 +6,12 @@ WARNING: this client can only be used to "Watch" for new randomness rounds and "Get" randomness rounds it has previously seen that are still in the cache. If you need to "Get" arbitrary rounds from the chain then you must combine this client with the http client. +You can Wrap multiple client together. The agnostic client builder must receive "WithChainInfo()" in order for it to validate randomness rounds it receives, or "WithChainHash()" and be combined with the HTTP client implementations so that chain information can be fetched from them. It is particularly important that rounds are verified since they can be delivered by any peer in the network. - -Example using "WithChainInfo()": - - package main - - import ( - "context" - - clock "github.com/jonboulle/clockwork" - pubsub "github.com/libp2p/go-libp2p-pubsub" - - "github.com/drand/drand/v2/client" - gclient "github.com/drand/drand/v2/client/lp2p" - "github.com/drand/drand/v2/common/chain" - "github.com/drand/drand/v2/common/log" - ) - - func main() { - ctx := context.Background() - lg := log.New(nil, log.DebugLevel, true) - clk := clock.NewRealClock() - - ps := newPubSub() - info := readChainInfo() - - c, err := client.New(ctx, lg, - gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), - client.WithChainInfo(info), - ) - } - - func newPubSub() *pubsub.Pubsub { - // ... - } - - func readChainInfo() *chain.Info { - // ... - } - -Example using "WithChainHash()" and combining it with a different client: - - package main - - import ( - "context" - "encoding/hex" - - clock "github.com/jonboulle/clockwork" - pubsub "github.com/libp2p/go-libp2p-pubsub" - - "github.com/drand/drand/v2/client" - "github.com/drand/drand/v2/client/http" - gclient "github.com/drand/drand/v2/client/lp2p" - "github.com/drand/drand/v2/common/log" - ) - - var urls = []string{ - "https://api.drand.sh", - "https://drand.cloudflare.com", - // ... - } - - var chainHash, _ = hex.DecodeString("8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce") - - func main() { - ctx := context.Background() - lg := log.New(nil, log.DebugLevel, true) - clk := clock.NewRealClock() - ps := newPubSub() - - c, err := client.New(ctx, lg, - gclient.WithPubsub(lg, ps, clk, gclient.DefaultBufferSize), - client.WithChainHash(chainHash), - client.From(http.ForURLs(ctx, lg, urls, chainHash)...), - ) - } - - func newPubSub() *pubsub.Pubsub { - // ... - } */ package lp2p From 790f78b42a1d3fdca0f6535576f03dc1051afe42 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 23 Jul 2024 18:59:21 +0200 Subject: [PATCH 25/28] Fixing all the last tests issues --- client/http/http.go | 4 ++-- client/test/http/mock/httpserver.go | 7 ++++++- internal/lib/cli.go | 23 ++++++++++++++++++++--- internal/lib/cli_test.go | 9 +-------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/client/http/http.go b/client/http/http.go index d3cbd19..2970466 100644 --- a/client/http/http.go +++ b/client/http/http.go @@ -59,7 +59,7 @@ func New(ctx context.Context, l log.Logger, url string, chainHash []byte, transp chainInfo, err := c.FetchChainInfo(ctx, chainHash) if err != nil { - return nil, err + return nil, fmt.Errorf("FetchChainInfo err: %w", err) } c.chainInfo = chainInfo @@ -243,7 +243,7 @@ func (h *httpClient) FetchChainInfo(ctx context.Context, chainHash []byte) (*cha chainInfo, err := chain2.InfoFromJSON(infoBody.Body) if err != nil { - resC <- httpInfoResponse{nil, fmt.Errorf("decoding response [chain2.InfoFromJSON]: %w", err)} + resC <- httpInfoResponse{nil, fmt.Errorf("decoding response [InfoFromJSON]: %w", err)} return } diff --git a/client/test/http/mock/httpserver.go b/client/test/http/mock/httpserver.go index c2618b7..dd00c65 100644 --- a/client/test/http/mock/httpserver.go +++ b/client/test/http/mock/httpserver.go @@ -40,21 +40,26 @@ func NewMockHTTPPublicServer(t *testing.T, badSecondRound bool, sch *crypto.Sche for i := 0; i < 3; i++ { protoInfo, err := server.ChainInfo(ctx, &drand.ChainInfoRequest{}) if err != nil { + t.Error("MockServer.ChainInfo error:", err) time.Sleep(10 * time.Millisecond) continue } chainInfo, err = chain.InfoFromProto(protoInfo) if err != nil { + t.Error("MockServer.InfoFromProto error:", err) time.Sleep(10 * time.Millisecond) continue } + break } if chainInfo == nil { t.Fatal("could not use server after 3 attempts.") } - handler.RegisterNewBeaconHandler(client, chainInfo.HashString()) + t.Log("MockServer.ChainInfo:", chainInfo) + + handler.RegisterDefaultBeaconHandler(handler.RegisterNewBeaconHandler(client, chainInfo.HashString())) listener, err := net.Listen("tcp", ":0") if err != nil { diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 5af2569..059b182 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -132,6 +132,7 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) var err error var hash []byte if groupPath := c.Path(GroupConfFlag.Name); groupPath != "" { + l.Debugw("parsing group-conf file") info, err = chainInfoFromGroupTOML(groupPath) if err != nil { l.Infow("Got a group conf file that is not a toml file. Trying it as a ChainInfo json file.", "path", groupPath) @@ -140,6 +141,8 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) return nil, fmt.Errorf("failed to decode group (%s) : %w", groupPath, err) } } + l.Debugw("parsing group-conf file, successful") + opts = append(opts, pubClient.WithChainInfo(info)) } @@ -154,6 +157,7 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) if len(grc) > 0 { clients = append(clients, grc...) } + l.Debugw("built GRPC Client", "successful", len(grc)) if c.String(HashFlag.Name) != "" { hash, err = hex.DecodeString(c.String(HashFlag.Name)) @@ -183,6 +187,8 @@ func Create(c *cli.Context, withInstrumentation bool, opts ...pubClient.Option) if len(gc) > 0 { clients = append(clients, gc...) } + l.Debugw("built HTTP Client", "successful", len(gc)) + if info != nil && hash != nil && !bytes.Equal(hash, info.Hash()) { return nil, fmt.Errorf( "%w for beacon %s : expected %v != info %v", @@ -244,9 +250,17 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta var hc client.Client var info *chainCommon.Info - l.Infow("Building HTTP clients", "hash", len(hash), "urls", c.StringSlice(URLFlag.Name)) + urls := c.StringSlice(URLFlag.Name) + + l.Infow("Building HTTP clients", "hash", len(hash), "urls", len(urls)) + + // we return an empty list if no URLs were provided + if len(urls) == 0 { + return clients, nil, nil + } - for _, url := range c.StringSlice(URLFlag.Name) { + for _, url := range urls { + l.Debugw("trying to instantiate http client", "url", url) hc, err = http2.New(ctx, l, url, hash, nhttp.DefaultTransport) if err != nil { l.Warnw("", "client", "failed to load URL", "url", url, "err", err) @@ -262,6 +276,7 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta clients = append(clients, hc) } + // do we want to error out or not if all provided URL failed to instantiate a client? if len(skipped) == len(c.StringSlice(URLFlag.Name)) { return nil, nil, errors.New("all URLs failed to be used for creating a http client") } @@ -272,10 +287,12 @@ func buildHTTPClients(c *cli.Context, l log.Logger, hash []byte, withInstrumenta return nil, nil, errors.New("mismatch between retrieved chain info and provided hash") } + // we re-try dialing the skipped remotes, just in case, but that's the last time, we won't be dialing these again + // later in case they fail. for _, url := range skipped { hc, err = http2.NewWithInfo(l, url, info, nhttp.DefaultTransport) if err != nil { - l.Warnw("", "client", "failed to load URL", "url", url, "err", err) + l.Warnw("", "client", "failed to load URL again", "url", url, "err", err) continue } clients = append(clients, hc) diff --git a/internal/lib/cli_test.go b/internal/lib/cli_test.go index e2bfdbe..9515cdd 100644 --- a/internal/lib/cli_test.go +++ b/internal/lib/cli_test.go @@ -2,7 +2,6 @@ package lib import ( "bytes" - "context" "encoding/hex" "errors" "os" @@ -11,8 +10,6 @@ import ( "testing" "time" - "github.com/drand/drand/v2/test/mock" - clock "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" @@ -64,11 +61,7 @@ func TestClientLib(t *testing.T) { addr, info, cancel, _ := httpmock.NewMockHTTPPublicServer(t, false, sch, clk) defer cancel() - time.Sleep(time.Second) - - grpcLis, _ := mock.NewMockGRPCPublicServer(t, lg, ":0", false, sch, clk) - go grpcLis.Start() - defer grpcLis.Stop(context.Background()) + t.Log("Started mockserver at", addr) args := []string{"mock-client", "--url", "http://" + addr, "--insecure"} err = run(lg, args) From dd8a9291889bd3326a842dbf073cf9367caf3e51 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 23 Jul 2024 19:02:50 +0200 Subject: [PATCH 26/28] updating deps --- go.mod | 56 +++++++++++++------------- go.sum | 123 +++++++++++++++++++++++++-------------------------------- 2 files changed, 82 insertions(+), 97 deletions(-) diff --git a/go.mod b/go.mod index 44e084e..5ac5081 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,17 @@ go 1.22 require ( github.com/BurntSushi/toml v1.4.0 - github.com/drand/drand/v2 v2.0.1 + github.com/drand/drand/v2 v2.0.2 github.com/drand/kyber v1.3.1 github.com/google/uuid v1.6.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 + github.com/hashicorp/consul/sdk v0.16.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 - github.com/libp2p/go-libp2p v0.35.1 + github.com/libp2p/go-libp2p v0.35.4 github.com/libp2p/go-libp2p-pubsub v0.11.0 github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multiaddr-dns v0.3.1 @@ -22,7 +23,7 @@ require ( github.com/prometheus/client_golang v1.19.1 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.2 - golang.org/x/crypto v0.24.0 + golang.org/x/crypto v0.25.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 ) @@ -55,15 +56,14 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.1 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 // indirect + github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/hashicorp/consul/sdk v0.16.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -106,22 +106,22 @@ require ( github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pion/datachannel v1.5.6 // indirect - github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.27 // indirect + github.com/pion/datachannel v1.5.8 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/ice/v2 v2.3.31 // indirect github.com/pion/interceptor v0.1.29 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.6 // indirect - github.com/pion/sctp v1.8.17 // indirect + github.com/pion/rtp v1.8.7 // indirect + github.com/pion/sctp v1.8.19 // indirect github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/srtp/v2 v2.0.20 // indirect github.com/pion/stun v0.6.1 // indirect - github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/transport/v2 v2.2.8 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.44 // indirect + github.com/pion/webrtc/v3 v3.2.49 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -132,33 +132,33 @@ require ( github.com/raulk/go-watchdog v1.3.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/wlynxg/anet v0.0.3 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.10 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/dig v1.17.1 // indirect go.uber.org/fx v1.22.1 // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/tools v0.22.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + golang.org/x/tools v0.23.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 267aba6..1032b15 100644 --- a/go.sum +++ b/go.sum @@ -65,7 +65,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -89,8 +88,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/drand/drand/v2 v2.0.1 h1:UGnzvBUAEOolNVGaz9UzZHdIhf55mjZbWg4kjotDbHk= -github.com/drand/drand/v2 v2.0.1/go.mod h1:SfzrKVexJwhwDral4tqS/E2bPTIEGC9P6H3DP/DXNmI= +github.com/drand/drand/v2 v2.0.2 h1:F0cvopmZWZA8NLRnpXE2+qVR13aNQZeCElYlWswcigM= +github.com/drand/drand/v2 v2.0.2/go.mod h1:nWBj4w7TA3R8xCoyLzkmsESjTlg4QgNSFAiRR9qZXt8= github.com/drand/kyber v1.3.1 h1:E0p6M3II+loMVwTlAp5zu4+GGZFNiRfq02qZxzw2T+Y= github.com/drand/kyber v1.3.1/go.mod h1:f+mNHjiGT++CuueBrpeMhFNdKZAsy0tu03bKq9D5LPA= github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= @@ -139,8 +138,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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= @@ -165,8 +164,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg= -github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8 h1:ssNFCCVmib/GQSzx3uCWyfMgOamLGWuGqlMS77Y1m3Y= +github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 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.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -262,8 +261,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 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.35.1 h1:Hm7Ub2BF+GCb14ojcsEK6WAy5it5smPDK02iXSZLl50= -github.com/libp2p/go-libp2p v0.35.1/go.mod h1:Dnkgba5hsfSv5dvvXC8nfqk44hH0gIKKno+HOMU0fdc= +github.com/libp2p/go-libp2p v0.35.4 h1:FDiBUYLkueFwsuNJUZaxKRdpKvBOWU64qQPL768bSeg= +github.com/libp2p/go-libp2p v0.35.4/go.mod h1:RKCDNt30IkFipGL0tl8wQW/3zVWEGFUZo8g2gAKxwjU= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= @@ -356,13 +355,13 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= -github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= +github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= -github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.27 h1:FF2O+hKUymskFTeyDvh+XwsNu5KBVhfihv6mtrMb8HQ= -github.com/pion/ice/v2 v2.3.27/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.31 h1:qag/YqiOn5qPi0kgeVdsytxjx8szuriWSIeXKu8dDQc= +github.com/pion/ice/v2 v2.3.31/go.mod h1:8fac0+qftclGy1tYd/nfwfHC729BLaxtVqMdMVCAVPU= github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -375,35 +374,32 @@ github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9 github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= -github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= -github.com/pion/sctp v1.8.17 h1:uK1VChU9C/J3Sj/Cq6cwEGtx2Gludgoi5zwZBZzWNT0= -github.com/pion/sctp v1.8.17/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/rtp v1.8.7 h1:qslKkG8qxvQ7hqaxkmL7Pl0XcUm+/Er7nMnu6Vq+ZxM= +github.com/pion/rtp v1.8.7/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.19 h1:2CYuw+SQ5vkQ9t0HdOPccsCz1GQMDuVy5PglLgKVBW8= +github.com/pion/sctp v1.8.19/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= -github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= +github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= -github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.8 h1:HzsqGBChgtF4Cj47gu51l5hONuK/NwgbZL17CMSuwS0= +github.com/pion/transport/v2 v2.2.8/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.44 h1:wL2X6xSVneYvNRWMdroHoiNAkF2rM6IIhV/oIz+iwJs= -github.com/pion/webrtc/v3 v3.2.44/go.mod h1:WRHWtbUNNtph0/FWtExX8cQl4EIpPrZec6gQf1tV6GE= +github.com/pion/webrtc/v3 v3.2.49 h1:G0DfKWeA++CBH7RcwB7M4msg9t/euEnFz638PYB6Ipg= +github.com/pion/webrtc/v3 v3.2.49/go.mod h1:s+tiQ44KWdJJkEw/oOoW24fW0ZEHlgOd3QyT90bqHeM= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -497,6 +493,8 @@ github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= 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/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= @@ -511,22 +509,22 @@ go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYr go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= -go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -564,16 +562,13 @@ 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.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 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= @@ -609,13 +604,10 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -664,11 +656,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -676,18 +665,14 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= @@ -715,8 +700,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= 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= @@ -735,10 +720,10 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade h1:WxZOF2yayUHpHSbUE6NMzumUzBxYc3YGwo0YHnbzsJY= +google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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= From 30890a097a671fcd5b78cbad0fcd6ae4c9e98651 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Tue, 23 Jul 2024 19:43:05 +0200 Subject: [PATCH 27/28] Getting rid of datastore backed peerstore Using the in-memory one instead --- .golangci.yml | 2 + client/http/example_test.go | 8 +++- client/lp2p/client.go | 2 +- client/lp2p/client_test.go | 15 +----- client/lp2p/example_test.go | 14 +----- client/lp2p/validator.go | 4 +- client/optimizing.go | 2 +- go.mod | 16 +------ go.sum | 92 +++---------------------------------- gossip-relay/main.go | 12 +++-- internal/cli.go | 3 +- internal/lib/cli.go | 13 +----- internal/lp2p/ctor.go | 12 ++--- internal/lp2p/relaynode.go | 10 +--- 14 files changed, 41 insertions(+), 164 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 7e166cb..ab2547f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -30,6 +30,8 @@ issues: linters: - forbidigo # we use Println in our UX - goconst # we re-use some strings in our flags + - path: client/http + text: "unexported-return" run: skip-dirs: - demo diff --git a/client/http/example_test.go b/client/http/example_test.go index ad7857e..c9daa76 100644 --- a/client/http/example_test.go +++ b/client/http/example_test.go @@ -10,8 +10,13 @@ import ( "github.com/drand/drand/v2/crypto" ) -func ExampleHttpNew() { +func Example_http_New() { chainhash, err := hex.DecodeString("52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971") + if err != nil { + // we recommend to handle errors as you wish rather than panicking + panic(err) + } + client, err := http.New(context.Background(), nil, "http://api.drand.sh", chainhash, nil) if err != nil { panic(err) @@ -42,5 +47,6 @@ func ExampleHttpNew() { } fmt.Printf("got beacon: round=%d; randomness=%x\n", result.GetRound(), result.GetRandomness()) + //output: got beacon: round=1234; randomness=9ead58abb451d8f521338c43ba5595610642a0c07d0e9babeaae6a98787629de } diff --git a/client/lp2p/client.go b/client/lp2p/client.go index ecd1230..b2c0178 100644 --- a/client/lp2p/client.go +++ b/client/lp2p/client.go @@ -66,7 +66,7 @@ func PubSubTopic(h string) string { // NewWithPubsub creates a gossip randomness client. If the logger l is nil, it will default to // a default Logger, // -//nolint:funlen,lll // This is a long line +//nolint:funlen,lll,gocyclo // This is a long line func NewWithPubsub(l log.Logger, ps *pubsub.PubSub, info *chain.Info, cache client2.Cache, clk clock.Clock, bufferSize int) (*Client, error) { if info == nil { return nil, fmt.Errorf("no chain supplied for joining") diff --git a/client/lp2p/client_test.go b/client/lp2p/client_test.go index 8968f30..7186701 100644 --- a/client/lp2p/client_test.go +++ b/client/lp2p/client_test.go @@ -10,7 +10,6 @@ import ( "time" "github.com/hashicorp/consul/sdk/freeport" - bds "github.com/ipfs/go-ds-badger2" clock "github.com/jonboulle/clockwork" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" @@ -180,24 +179,14 @@ func TestHTTPClientTestFunc(t *testing.T) { } func newTestClient(t *testing.T, relayMultiaddr []ma.Multiaddr, info *chain2.Info, clk clock.Clock) (*Client, error) { - dataDir := t.TempDir() identityDir := t.TempDir() - ds, err := bds.NewDatastore(dataDir, nil) - if err != nil { - return nil, err - } + lg := log.New(nil, log.DebugLevel, true) priv, err := lp2p.LoadOrCreatePrivKey(path.Join(identityDir, "identity.key"), lg) if err != nil { return nil, err } - h, ps, err := lp2p.ConstructHost( - ds, - priv, - "/ip4/0.0.0.0/tcp/"+strconv.Itoa(freeport.GetOne(t)), - relayMultiaddr, - lg, - ) + h, ps, err := lp2p.ConstructHost(priv, "/ip4/0.0.0.0/tcp/"+strconv.Itoa(freeport.GetOne(t)), relayMultiaddr, lg) if err != nil { return nil, err } diff --git a/client/lp2p/example_test.go b/client/lp2p/example_test.go index 0d7d7e3..07a8f29 100644 --- a/client/lp2p/example_test.go +++ b/client/lp2p/example_test.go @@ -6,11 +6,12 @@ import ( "fmt" "time" + clock "github.com/jonboulle/clockwork" + gclient "github.com/drand/drand-cli/client/lp2p" "github.com/drand/drand/v2/common" "github.com/drand/drand/v2/common/chain" "github.com/drand/drand/v2/common/log" - clock "github.com/jonboulle/clockwork" ) const ( @@ -19,17 +20,6 @@ const ( relayP2PAddr2 = "/dnsaddr/api2.drand.sh" relayP2PAddr3 = "/dnsaddr/api3.drand.sh" - jsonDefaultInfo = `{ - "genesis_time": 1595431050, - "groupHash": "176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a", - "hash": "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce", - "metadata": { - "beaconID": "default" - }, - "period": 30, - "public_key": "868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31", - "schemeID": "pedersen-bls-chained" -}` // jsonQuicknetInfo, can be hardcoded since these don't change over time jsonQuicknetInfo = `{ "genesis_time": 1692803367, diff --git a/client/lp2p/validator.go b/client/lp2p/validator.go index c88a2c9..8a6b99b 100644 --- a/client/lp2p/validator.go +++ b/client/lp2p/validator.go @@ -23,7 +23,7 @@ func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk c if info != nil { scheme, _ = crypto.GetSchemeByID(info.Scheme) } - return func(ctx context.Context, p peer.ID, m *pubsub.Message) pubsub.ValidationResult { + return func(_ context.Context, p peer.ID, m *pubsub.Message) pubsub.ValidationResult { rand := &drand.PublicRandResponse{} err := proto.Unmarshal(m.Data, rand) if err != nil { @@ -31,7 +31,7 @@ func randomnessValidator(info *chain2.Info, cache client.Cache, c *Client, clk c return pubsub.ValidationReject } - c.log.Debugw("", "gossip validator", "Received new round", "round", rand.GetRound()) + c.log.Debugw("", "gossip validator", "Received new round", "round", rand.GetRound(), "fromPeerID", p.String()) if info == nil { c.log.Warnw("", "gossip validator", "Not validating received randomness due to lack of trust root.") diff --git a/client/optimizing.go b/client/optimizing.go index db45fc5..82e24b3 100644 --- a/client/optimizing.go +++ b/client/optimizing.go @@ -253,7 +253,7 @@ LOOP: stats = append(stats, rr.stat) res = rr.result if rr.err != nil && !errors.Is(rr.err, common.ErrEmptyClientUnsupportedGet) { - err = fmt.Errorf("%v - %w", err, rr.err) + err = errors.Join(err, rr.err) } else if rr.err == nil { err = nil } diff --git a/go.mod b/go.mod index 5ac5081..024a907 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,6 @@ require ( github.com/hashicorp/consul/sdk v0.16.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru v1.0.2 - github.com/ipfs/go-datastore v0.6.0 - github.com/ipfs/go-ds-badger2 v0.1.3 github.com/jonboulle/clockwork v0.4.0 github.com/libp2p/go-libp2p v0.35.4 github.com/libp2p/go-libp2p-pubsub v0.11.0 @@ -32,7 +30,6 @@ require ( github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -40,12 +37,8 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/drand/kyber-bls12381 v0.3.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.1.0 // indirect @@ -56,23 +49,18 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/golang-lru/arc/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/go-cid v0.4.1 // 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/jmoiron/sqlx v1.4.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -157,8 +145,8 @@ require ( golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.23.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 1032b15..afd8860 100644 --- a/go.sum +++ b/go.sum @@ -9,18 +9,12 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/ardanlabs/darwin/v2 v2.0.0 h1:XCisQMgQ5EG+ZvSEcADEo+pyfIMKyWAGnn5o2TgriYE= github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfKxvSy1HMhoes= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -36,8 +30,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.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= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= @@ -52,14 +44,10 @@ github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5U github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= @@ -74,17 +62,6 @@ github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5il github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= -github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -95,8 +72,6 @@ github.com/drand/kyber v1.3.1/go.mod h1:f+mNHjiGT++CuueBrpeMhFNdKZAsy0tu03bKq9D5 github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= @@ -127,6 +102,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -138,8 +114,6 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= -github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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= @@ -149,10 +123,6 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -166,8 +136,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8 h1:ssNFCCVmib/GQSzx3uCWyfMgOamLGWuGqlMS77Y1m3Y= github.com/google/pprof v0.0.0-20240722153945-304e4f0156b8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -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.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -193,38 +161,18 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ= -github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/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.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= -github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= -github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= -github.com/ipfs/go-ds-badger2 v0.1.3 h1:Zo9JicXJ1DmXTN4KOw7oPXkspZ0AWHcAFCP1tQKnegg= -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-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -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= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= @@ -237,7 +185,6 @@ 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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= @@ -246,7 +193,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv 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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -280,7 +226,6 @@ github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8S github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= 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/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= @@ -304,8 +249,6 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8Rv github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -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/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -343,6 +286,7 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= 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 v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= @@ -354,7 +298,6 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= @@ -424,7 +367,6 @@ github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= 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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -459,15 +401,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 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/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= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -484,10 +419,7 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= @@ -495,7 +427,6 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -527,7 +458,6 @@ go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+ go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= @@ -539,11 +469,9 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -551,10 +479,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -575,7 +501,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -629,12 +554,10 @@ golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-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-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -647,10 +570,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -689,9 +610,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm 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= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -722,8 +640,12 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade h1:WxZOF2yayUHpHSbUE6NMzumUzBxYc3YGwo0YHnbzsJY= google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a h1:YIa/rzVqMEokBkPtydCkx1VLmv3An1Uw7w1P1m6EhOY= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys= google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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= @@ -741,7 +663,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -755,7 +676,6 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh 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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= diff --git a/gossip-relay/main.go b/gossip-relay/main.go index f3dd64d..5108145 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -32,7 +32,7 @@ func main() { // See https://cli.urfave.org/v2/examples/bash-completions/#enabling for how to turn on. app.EnableBashCompletion = true - cli.VersionPrinter = func(c *cli.Context) { + cli.VersionPrinter = func(_ *cli.Context) { fmt.Printf("drand gossip-relay relay %s (date %v, commit %v)\n", app.Version, buildDate, gitCommit) } @@ -86,7 +86,11 @@ var runCmd = &cli.Command{ }...), Action: func(cctx *cli.Context) error { if cctx.IsSet(lib.HashFlag.Name) || cctx.IsSet(lib.GroupConfFlag.Name) { - fmt.Printf("--%s and --%s are deprecated. Use --%s or --%s instead\n", lib.HashFlag.Name, lib.GroupConfFlag, lib.HashListFlag.Name, lib.GroupConfListFlag.Name) + fmt.Printf("--%s and --%s are deprecated. Use --%s or --%s instead\n", + lib.HashFlag.Name, + lib.GroupConfFlag, + lib.HashListFlag.Name, + lib.GroupConfListFlag.Name) } switch { @@ -212,7 +216,9 @@ var clientCmd = &cli.Command{ if cctx.IsSet(lib.GroupConfFlag.Name) { return fmt.Errorf("please do not use both --%s and --%s at the same time", lib.GroupConfFlag.Name, lib.GroupConfListFlag.Name) } - cctx.Set(lib.GroupConfFlag.Name, groupConfs[0]) + if err := cctx.Set(lib.GroupConfFlag.Name, groupConfs[0]); err != nil { + return fmt.Errorf("unable to set GroupConfFlag: %w", err) + } } c, err := lib.Create(cctx, false) if err != nil { diff --git a/internal/cli.go b/internal/cli.go index 181f9f6..da66262 100644 --- a/internal/cli.go +++ b/internal/cli.go @@ -126,8 +126,7 @@ func getPublicRandomness(cctx *cli.Context) error { if err != nil { return err } - json.NewEncoder(cctx.App.Writer).Encode(round) - return nil + return json.NewEncoder(cctx.App.Writer).Encode(round) } func getChainInfo(cctx *cli.Context) error { diff --git a/internal/lib/cli.go b/internal/lib/cli.go index 059b182..4f5a5fc 100644 --- a/internal/lib/cli.go +++ b/internal/lib/cli.go @@ -13,7 +13,6 @@ import ( "github.com/BurntSushi/toml" "github.com/google/uuid" - bds "github.com/ipfs/go-ds-badger2" clock "github.com/jonboulle/clockwork" pubsub "github.com/libp2p/go-libp2p-pubsub" ma "github.com/multiformats/go-multiaddr" @@ -330,10 +329,6 @@ func buildGossipClient(c *cli.Context, l log.Logger) ([]pubClient.Option, error) func buildClientHost(l log.Logger, clientListenAddr string, relayMultiaddr []ma.Multiaddr) (*pubsub.PubSub, error) { clientID := uuid.New().String() - ds, err := bds.NewDatastore(path.Join(os.TempDir(), "drand-"+clientID+"-datastore"), nil) - if err != nil { - return nil, err - } priv, err := lp2p.LoadOrCreatePrivKey(path.Join(os.TempDir(), "drand-"+clientID+"-id"), l) if err != nil { return nil, err @@ -353,13 +348,7 @@ func buildClientHost(l log.Logger, clientListenAddr string, relayMultiaddr []ma. listen = fmt.Sprintf("/ip4/%s/tcp/%s", bindHost, clientListenAddr) } - _, ps, err := lp2p.ConstructHost( - ds, - priv, - listen, - relayMultiaddr, - l, - ) + _, ps, err := lp2p.ConstructHost(priv, listen, relayMultiaddr, l) if err != nil { return nil, err } diff --git a/internal/lp2p/ctor.go b/internal/lp2p/ctor.go index 5fb019e..2929919 100644 --- a/internal/lp2p/ctor.go +++ b/internal/lp2p/ctor.go @@ -10,15 +10,13 @@ import ( "path" "time" - "github.com/ipfs/go-datastore" - "github.com/ipfs/go-datastore/namespace" "github.com/libp2p/go-libp2p" pubsub "github.com/libp2p/go-libp2p-pubsub" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoreds" + "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" "github.com/libp2p/go-libp2p/p2p/net/connmgr" "github.com/libp2p/go-libp2p/p2p/security/noise" libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" @@ -48,12 +46,10 @@ func PubSubTopic(h string) string { } // ConstructHost build a libp2p host configured for relaying drand randomness over pubsub. -func ConstructHost(ds datastore.Datastore, priv crypto.PrivKey, listenAddr string, - bootstrap []ma.Multiaddr, log dlog.Logger) (host.Host, *pubsub.PubSub, error) { +func ConstructHost(priv crypto.PrivKey, listenAddr string, bootstrap []ma.Multiaddr, log dlog.Logger) (host.Host, *pubsub.PubSub, error) { ctx := context.Background() - pstoreDs := namespace.Wrap(ds, datastore.NewKey("/peerstore")) - pstore, err := pstoreds.NewPeerstore(ctx, pstoreDs, pstoreds.DefaultOpts()) + pstore, err := pstoremem.NewPeerstore() if err != nil { return nil, nil, fmt.Errorf("creating peerstore: %w", err) } @@ -82,7 +78,7 @@ func ConstructHost(ds datastore.Datastore, priv crypto.PrivKey, listenAddr strin libp2p.Security(libp2ptls.ID, libp2ptls.New), libp2p.Security(noise.ID, noise.New)), libp2p.DisableRelay(), - // libp2p.Peerstore(pstore), depends on https://github.com/libp2p/go-libp2p-peerstore/issues/153 + libp2p.Peerstore(pstore), libp2p.UserAgent(userAgent), libp2p.ConnectionManager(cmgr), } diff --git a/internal/lp2p/relaynode.go b/internal/lp2p/relaynode.go index c8a48e4..68563f0 100644 --- a/internal/lp2p/relaynode.go +++ b/internal/lp2p/relaynode.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - bds "github.com/ipfs/go-ds-badger2" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" @@ -35,7 +34,6 @@ type GossipRelayConfig struct { type GossipRelayNode struct { l log.Logger bootstrap []ma.Multiaddr - ds *bds.Datastore priv crypto.PrivKey h host.Host ps *pubsub.PubSub @@ -55,17 +53,12 @@ func NewGossipRelayNode(l log.Logger, cfg *GossipRelayConfig) (*GossipRelayNode, return nil, fmt.Errorf("parsing peer-with: %w", err) } - ds, err := bds.NewDatastore(cfg.DataDir, nil) - if err != nil { - return nil, fmt.Errorf("opening datastore: %w", err) - } - priv, err := LoadOrCreatePrivKey(cfg.IdentityPath, l) if err != nil { return nil, fmt.Errorf("loading p2p key: %w", err) } - h, ps, err := ConstructHost(ds, priv, cfg.Addr, bootstrap, l) + h, ps, err := ConstructHost(priv, cfg.Addr, bootstrap, l) if err != nil { return nil, fmt.Errorf("constructing host: %w", err) } @@ -87,7 +80,6 @@ func NewGossipRelayNode(l log.Logger, cfg *GossipRelayConfig) (*GossipRelayNode, g := &GossipRelayNode{ l: l, bootstrap: bootstrap, - ds: ds, priv: priv, h: h, ps: ps, From 8e4c811f6930193fe05d0a45ab6c6751acf248f3 Mon Sep 17 00:00:00 2001 From: Yolan Romailler Date: Wed, 24 Jul 2024 16:28:07 +0200 Subject: [PATCH 28/28] fixing flag issue in gossip relays --- gossip-relay/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gossip-relay/main.go b/gossip-relay/main.go index 5108145..69c7a9f 100644 --- a/gossip-relay/main.go +++ b/gossip-relay/main.go @@ -83,6 +83,7 @@ var runCmd = &cli.Command{ storeFlag, listenFlag, metricsFlag, + lib.GRPCConnectFlag, }...), Action: func(cctx *cli.Context) error { if cctx.IsSet(lib.HashFlag.Name) || cctx.IsSet(lib.GroupConfFlag.Name) {