diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml new file mode 100644 index 0000000000..87c895d44c --- /dev/null +++ b/.github/workflows/link-check.yml @@ -0,0 +1,17 @@ +name: Markdown Link Checking +on: + pull_request: + push: + branches: + - "master" + +jobs: + check-links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' # show only broken links + use-verbose-mode: 'yes' + config-file: .github/workflows/markdown-links-config.json # for removing any false positives diff --git a/.github/workflows/markdown-links-config.json b/.github/workflows/markdown-links-config.json new file mode 100644 index 0000000000..505831a198 --- /dev/null +++ b/.github/workflows/markdown-links-config.json @@ -0,0 +1,22 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http://localhost" + }, + { + "pattern": "^https://twitter.com/" + }, + { + "pattern": "^https://opensource.org/" + } + ], + "aliveStatusCodes": [200], + "httpHeaders": [ + { + "urls": ["https://docs.github.com/"], + "headers": { + "Accept-Encoding": "*" + } + } + ] +} \ No newline at end of file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6f6d895d19..16d65d7217 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,25 +2,12 @@ name: Close and mark stale issue on: schedule: - - cron: '0 0 * * *' + - cron: '0 0 * * *' + +permissions: + issues: write + pull-requests: write jobs: stale: - - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/stale@v3 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.' - close-issue-message: 'This issue was closed because it is missing author input.' - stale-issue-label: 'kind/stale' - any-of-labels: 'need/author-input' - exempt-issue-labels: 'need/triage,need/community-input,need/maintainer-input,need/maintainers-input,need/analysis,status/blocked,status/in-progress,status/ready,status/deferred,status/inactive' - days-before-issue-stale: 6 - days-before-issue-close: 7 - enable-statistics: true + uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bec380212..b6ab14c177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Table Of Contents +- [v0.28.0](#v0280) - [v0.27.0](#v0270) - [v0.26.4](#v0264) - [v0.26.3](#v0263) @@ -8,6 +9,73 @@ - [v0.25.1](#v0251) - [v0.25.0](#v0250) +# [v0.28.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.28.0) + +## 🔦 Highlights + +### Smart Dialing + +This release introduces smart dialing logic. Currently, libp2p dials all addresses of a remote peer in parallel, and +aborts all outstanding dials as soon as the first one succeeds. +Dialing many addresses in parallel creates a lot of churn on the client side, and unnecessary load on the network and +on the server side, and is heavily discouraged by the networking community (see [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305) for example). + +When connecting to a peer we first determine the order to dial its addresses. This ranking logic considers a number of corner cases +described in detail in the documentation of the swarm package (`swarm.DefaultDialRanker`). +At a high level, this is what happens: +* If a peer offers a WebTransport and a QUIC address (on the same IP:port), the QUIC address is preferred. +* If a peer has a QUIC and a TCP address, the QUIC address is dialed first. Only if the connection attempt doesn't succeed within 250ms, a TCP connection is started. + +Our measurements on the IPFS network show that for >90% of established libp2p connections, the first connection attempt succeeds, +leading a dramatic decrease in the number of aborted connection attempts. + +We also added new metrics to the swarm Grafana dashboard, showing: +* The number of connection attempts it took to establish a connection +* The delay introduced by the ranking logic + +This feature should be safe to enable for nodes running in data centers and for most nodes in home networks. +However, there are some (mostly home and corporate networks) that block all UDP traffic. If enabled, the current implementation +of the smart dialing logic will lead to a regression, since it preferes QUIC addresses over TCP addresses. Nodes would still be +able to connect, but connection establishment of the TCP connection would be delayed by 250ms. + +In a future release (see #1605 for details), we will introduce a feature called blackhole detection. By observing the outcome of +QUIC connection attempts, we can determine if UDP traffic is blocked (namely, if all QUIC connection attempts fail), and stop +dialing QUIC in this case altogether. Once this detection logic is in place, smart dialing will be enabled by default. + +### More Metrics! +Since the last release, we've added metrics for: +* [Holepunching](https://github.com/libp2p/go-libp2p/pull/2246) +* Smart Dialing (see above) + +### WebTransport +* [#2251](https://github.com/libp2p/go-libp2p/pull/2251): Infer public WebTransport address from `quic-v1` addresses if both transports are using the same port for both quic-v1 and WebTransport addresses. +* [#2271](https://github.com/libp2p/go-libp2p/pull/2271): Only add certificate hashes to WebTransport mulitaddress if listening on WebTransport + +## Housekeeping updates +* Identify + * [#2303](https://github.com/libp2p/go-libp2p/pull/2303): Don't send default protocol version + * Prevent polluting PeerStore with local addrs + * [#2325](https://github.com/libp2p/go-libp2p/pull/2325): Don't save signed peer records + * [#2300](https://github.com/libp2p/go-libp2p/pull/2300): Filter received addresses based on the node's remote address +* WebSocket + * [#2280](https://github.com/libp2p/go-libp2p/pull/2280): Reverted back to the Gorilla library for WebSocket +* NAT + * [#2248](https://github.com/libp2p/go-libp2p/pull/2248): Move NAT mapping logic out of the host + +## 🐞 Bugfixes +* Identify + * [Reject signed peer records on peer ID mismatch](https://github.com/libp2p/go-libp2p/commit/8d771355b41297623e05b04a865d029a2522a074) + * [#2299](https://github.com/libp2p/go-libp2p/pull/2299): Avoid spuriously pushing updates +* Swarm + * [#2322](https://github.com/libp2p/go-libp2p/pull/2322): Dedup addresses to dial + * [#2284](https://github.com/libp2p/go-libp2p/pull/2284): Change maps with multiaddress keys to use strings +* QUIC + * [#2262](https://github.com/libp2p/go-libp2p/pull/2262): Prioritize listen connections for reuse + * [#2276](https://github.com/libp2p/go-libp2p/pull/2276): Don't panic when quic-go's accept call errors + * [#2263](https://github.com/libp2p/go-libp2p/pull/2263): Fix race condition when generating random holepunch packet + +**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.27.0...v0.28.0 + # [v0.27.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.27.0) ### Breaking Changes @@ -82,7 +150,7 @@ Since the last release, we've added additional metrics to different components. Metrics were added to: * [AutoNat](https://github.com/libp2p/go-libp2p/pull/2086): Current Reachability Status and Confidence, Client and Server DialResponses, Server DialRejections. The dashboard is [available here](https://github.com/libp2p/go-libp2p/blob/master/dashboards/autonat/autonat.json). * Swarm: - - [Early Muxer Selection](https://github.com/libp2p/go-libp2p/pull/2119): Added early_muxer label indicating whether a connection was established using early muxer selection. + - [Early Muxer Selection](https://github.com/libp2p/go-libp2p/pull/2119): Added early_muxer label indicating whether a connection was established using early muxer selection. - [IP Version](https://github.com/libp2p/go-libp2p/pull/2114): Added ip_version label to connection metrics * Identify: - Metrics for Identify, IdentifyPush, PushesTriggered (https://github.com/libp2p/go-libp2p/pull/2069) @@ -127,8 +195,8 @@ Fix some test-utils used by https://github.com/libp2p/go-libp2p-kad-dht ### Metrics We've started instrumenting the entire stack. In this release, we're adding metrics for: -* the swarm: tracking incoming and outgoing connections, transports, security protocols and stream multiplexers in use: (https://github.com/libp2p/go-libp2p/blob/master/p2p/net/swarm/grafana-dashboards/swarm.json) -* the event bus: tracking how different events are propagated through the stack and to external consumers (https://github.com/libp2p/go-libp2p/blob/master/p2p/host/eventbus/grafana-dashboards/eventbus.json) +* the swarm: tracking incoming and outgoing connections, transports, security protocols and stream multiplexers in use: (https://github.com/libp2p/go-libp2p/blob/master/dashboards/swarm/swarm.json) +* the event bus: tracking how different events are propagated through the stack and to external consumers (https://github.com/libp2p/go-libp2p/blob/master/dashboards/eventbus/eventbus.json) Our metrics effort is still ongoing, see https://github.com/libp2p/go-libp2p/issues/1356 for progress. We'll add metrics and dashboards for more libp2p components in a future release. @@ -155,7 +223,7 @@ We therefore concluded that it's safe to drop this code path altogether, and the * Introduces a new `ResourceLimits` type which uses `LimitVal` instead of ints so it can encode the above for the resources. * Changes `LimitConfig` to `PartialLimitConfig` and uses `ResourceLimits`. This along with the marshalling changes means you can now marshal the fact that some resource limit is set to block all. * Because the default is to use the defaults, this avoids the footgun of initializing the resource manager with 0 limits (that would block everything). - + In general, you can go from a resource config with defaults to a concrete one with `.Build()`. e.g. `ResourceLimits.Build() => BaseLimit`, `PartialLimitConfig.Build() => ConcreteLimitConfig`, `LimitVal.Build() => int`. See PR #2000 for more details. If you're using the defaults for the resource manager, there should be no changes needed. diff --git a/README.md b/README.md index 533a36f751..155f46654f 100644 --- a/README.md +++ b/README.md @@ -13,18 +13,16 @@
-# Table of Contents - +# Table of Contents - [Background](#background) - [Roadmap](#roadmap) - [Usage](#usage) - [Examples](#examples) -- [Development](#development) - - [Tests](#tests) - [Contribute](#contribute) -- [Supported Go Versions](#supported-go-versions) + - [Supported Go Versions](#supported-go-versions) +- [Notable Users](#notable-users) -## Background +# Background [libp2p](https://github.com/libp2p/specs) is a networking stack and library modularized out of [The IPFS Project](https://github.com/ipfs/ipfs), and bundled separately for other tools to use. > @@ -37,12 +35,12 @@ To learn more, check out the following resources: - [**js-libp2p implementation**](https://github.com/libp2p/js-libp2p) - [**rust-libp2p implementation**](https://github.com/libp2p/rust-libp2p) -## Roadmap +# Roadmap Our roadmap for go-libp2p can be found here: https://github.com/libp2p/go-libp2p/blob/master/ROADMAP.md -This document represents current projects the go-libp2p team is focused on and provides an estimation of completion targets. It is a completementary roadmap to the overarching libp2p project roadmap: https://github.com/libp2p/specs/blob/master/ROADMAP.md +This document represents current projects the go-libp2p team is focused on and provides an estimation of completion targets. It is a complementary roadmap to the overarching libp2p project roadmap: https://github.com/libp2p/specs/blob/master/ROADMAP.md -## Usage +# Usage This repository (`go-libp2p`) serves as the entrypoint to the universe of packages that compose the Go implementation of the libp2p stack. @@ -52,25 +50,25 @@ You can start using go-libp2p in your Go application simply by adding imports fr import "github.com/libp2p/go-libp2p" ``` -### Examples +## Examples Examples can be found in the [examples folder](examples). # Contribute -go-libp2p is part of [The IPFS Project](https://github.com/ipfs/ipfs), and is MIT-licensed open source software. We welcome contributions big and small! Take a look at the [community contributing notes](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md). Please make sure to check the [issues](https://github.com/ipfs/go-libp2p/issues). Search the closed ones before reporting things, and help us with the open ones. +go-libp2p is MIT-licensed open source software. We welcome contributions big and small! Take a look at the [community contributing notes](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md). Please make sure to check the [issues](https://github.com/libp2p/go-libp2p/issues). Search the closed ones before reporting things, and help us with the open ones. Guidelines: - read the [libp2p spec](https://github.com/libp2p/specs) -- ask questions or talk about things in our [discussion forums](https://discuss.libp2p.io), or open an [issue](https://github.com/libp2p/go-libp2p/issues) for bug reports, or #libp2p on freenode. +- ask questions or talk about things in our [discussion forums](https://discuss.libp2p.io), or open an [issue](https://github.com/libp2p/go-libp2p/issues) for bug reports, or #libp2p-implementers on [Filecoin slack](https://filecoin.io/slack). - ensure you are able to contribute (no legal issues please -- we use the DCO) -- get in touch with @marten-seemann about how best to contribute +- get in touch with @libp2p/go-libp2p-maintainers about how best to contribute - have fun! There's a few things you can do right now to help out: - - Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrasture behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically. + - Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically. - **Perform code reviews**. - **Add tests**. There can never be enough tests. @@ -99,4 +97,4 @@ Some notable users of go-libp2p are: - [Kairos](https://github.com/kairos-io/kairos) - A Kubernetes-focused, Cloud Native Linux meta-distribution. - [Oasis Core](https://github.com/oasisprotocol/oasis-core) - The consensus and runtime layers of the [Oasis protocol](https://oasisprotocol.org/). -Please open a pull request if you want your project to be added here. +Please open a pull request if you want your project (min. 250 GitHub stars) to be added here. diff --git a/config/config.go b/config/config.go index a3bd86f27b..cea8ef1314 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,7 @@ import ( blankhost "github.com/libp2p/go-libp2p/p2p/host/blank" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" routed "github.com/libp2p/go-libp2p/p2p/host/routed" "github.com/libp2p/go-libp2p/p2p/net/swarm" tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" @@ -123,6 +124,10 @@ type Config struct { DisableMetrics bool PrometheusRegisterer prometheus.Registerer + + DialRanker network.DialRanker + + SwarmOpts []swarm.Option } func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) { @@ -134,8 +139,8 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa if pnet.ForcePrivateNetwork && len(cfg.PSK) == 0 { log.Error("tried to create a libp2p node with no Private" + " Network Protector but usage of Private Networks" + - " is forced by the enviroment") - // Note: This is *also* checked the upgrader itself so it'll be + " is forced by the environment") + // Note: This is *also* checked the upgrader itself, so it'll be // enforced even *if* you don't use the libp2p constructor. return nil, pnet.ErrNotInPrivateNetwork } @@ -157,7 +162,7 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa return nil, err } - opts := make([]swarm.Option, 0, 6) + opts := cfg.SwarmOpts if cfg.Reporter != nil { opts = append(opts, swarm.WithMetrics(cfg.Reporter)) } @@ -173,6 +178,10 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa if cfg.MultiaddrResolver != nil { opts = append(opts, swarm.WithMultiaddrResolver(cfg.MultiaddrResolver)) } + if cfg.DialRanker != nil { + opts = append(opts, swarm.WithDialRanker(cfg.DialRanker)) + } + if enableMetrics { opts = append(opts, swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer)))) @@ -292,6 +301,10 @@ func (cfg *Config) NewNode() (host.Host, error) { return nil, err } + if !cfg.DisableMetrics { + rcmgr.MustRegisterWith(cfg.PrometheusRegisterer) + } + h, err := bhost.NewHost(swrm, &bhost.HostOpts{ EventBus: eventBus, ConnManager: cfg.ConnManager, @@ -393,7 +406,7 @@ func (cfg *Config) NewNode() (host.Host, error) { } // Pull out the pieces of the config that we _actually_ care about. - // Specifically, don't setup things like autorelay, listeners, + // Specifically, don't set up things like autorelay, listeners, // identify, etc. autoNatCfg := Config{ Transports: cfg.Transports, @@ -405,6 +418,7 @@ func (cfg *Config) NewNode() (host.Host, error) { Reporter: cfg.Reporter, PeerKey: autonatPrivKey, Peerstore: ps, + DialRanker: swarm.NoDelayDialRanker, } dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false) diff --git a/core/crypto/ecdsa.go b/core/crypto/ecdsa.go index 318dcac2b4..c936d502ac 100644 --- a/core/crypto/ecdsa.go +++ b/core/crypto/ecdsa.go @@ -49,7 +49,7 @@ func GenerateECDSAKeyPair(src io.Reader) (PrivKey, PubKey, error) { return GenerateECDSAKeyPairWithCurve(ECDSACurve, src) } -// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a speicified curve +// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a specified curve func GenerateECDSAKeyPairWithCurve(curve elliptic.Curve, src io.Reader) (PrivKey, PubKey, error) { priv, err := ecdsa.GenerateKey(curve, src) if err != nil { diff --git a/core/crypto/ed25519.go b/core/crypto/ed25519.go index 7cd72efbce..d6e3031c03 100644 --- a/core/crypto/ed25519.go +++ b/core/crypto/ed25519.go @@ -101,7 +101,7 @@ func (k *Ed25519PublicKey) Equals(o Key) bool { return bytes.Equal(k.k, edk.k) } -// Verify checks a signature agains the input data. +// Verify checks a signature against the input data. func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (success bool, err error) { defer func() { catch.HandlePanic(recover(), &err, "ed15519 signature verification") diff --git a/core/crypto/key.go b/core/crypto/key.go index 9133141c8d..3652c3cde0 100644 --- a/core/crypto/key.go +++ b/core/crypto/key.go @@ -90,7 +90,7 @@ type PrivKey interface { GetPublic() PubKey } -// PubKey is a public key that can be used to verifiy data signed with the corresponding private key +// PubKey is a public key that can be used to verify data signed with the corresponding private key type PubKey interface { Key @@ -106,7 +106,7 @@ func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) { return GenerateKeyPairWithReader(typ, bits, rand.Reader) } -// GenerateKeyPairWithReader returns a keypair of the given type and bitsize +// GenerateKeyPairWithReader returns a keypair of the given type and bit-size func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) { switch typ { case RSA: diff --git a/core/crypto/rsa_common.go b/core/crypto/rsa_common.go index c7e305439a..2b05eb6a35 100644 --- a/core/crypto/rsa_common.go +++ b/core/crypto/rsa_common.go @@ -12,9 +12,12 @@ const WeakRsaKeyEnv = "LIBP2P_ALLOW_WEAK_RSA_KEYS" var MinRsaKeyBits = 2048 +var maxRsaKeyBits = 8192 + // ErrRsaKeyTooSmall is returned when trying to generate or parse an RSA key // that's smaller than MinRsaKeyBits bits. In test var ErrRsaKeyTooSmall error +var ErrRsaKeyTooBig error = fmt.Errorf("rsa keys must be <= %d bits", maxRsaKeyBits) func init() { if _, ok := os.LookupEnv(WeakRsaKeyEnv); ok { diff --git a/core/crypto/rsa_go.go b/core/crypto/rsa_go.go index 7927d17d18..8981ba6aa6 100644 --- a/core/crypto/rsa_go.go +++ b/core/crypto/rsa_go.go @@ -14,12 +14,12 @@ import ( "github.com/minio/sha256-simd" ) -// RsaPrivateKey is an rsa private key +// RsaPrivateKey is a rsa private key type RsaPrivateKey struct { sk rsa.PrivateKey } -// RsaPublicKey is an rsa public key +// RsaPublicKey is a rsa public key type RsaPublicKey struct { k rsa.PublicKey @@ -31,6 +31,9 @@ func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) { if bits < MinRsaKeyBits { return nil, nil, ErrRsaKeyTooSmall } + if bits > maxRsaKeyBits { + return nil, nil, ErrRsaKeyTooBig + } priv, err := rsa.GenerateKey(src, bits) if err != nil { return nil, nil, err @@ -68,7 +71,7 @@ func (pk *RsaPublicKey) Raw() (res []byte, err error) { // Equals checks whether this key is equal to another func (pk *RsaPublicKey) Equals(k Key) bool { - // make sure this is an rsa public key + // make sure this is a rsa public key other, ok := (k).(*RsaPublicKey) if !ok { return basicEquals(pk, k) @@ -101,7 +104,7 @@ func (sk *RsaPrivateKey) Raw() (res []byte, err error) { // Equals checks whether this key is equal to another func (sk *RsaPrivateKey) Equals(k Key) bool { - // make sure this is an rsa public key + // make sure this is a rsa public key other, ok := (k).(*RsaPrivateKey) if !ok { return basicEquals(sk, k) @@ -124,6 +127,9 @@ func UnmarshalRsaPrivateKey(b []byte) (key PrivKey, err error) { if sk.N.BitLen() < MinRsaKeyBits { return nil, ErrRsaKeyTooSmall } + if sk.N.BitLen() > maxRsaKeyBits { + return nil, ErrRsaKeyTooBig + } return &RsaPrivateKey{sk: *sk}, nil } @@ -141,6 +147,9 @@ func UnmarshalRsaPublicKey(b []byte) (key PubKey, err error) { if pk.N.BitLen() < MinRsaKeyBits { return nil, ErrRsaKeyTooSmall } + if pk.N.BitLen() > maxRsaKeyBits { + return nil, ErrRsaKeyTooBig + } return &RsaPublicKey{k: *pk}, nil } diff --git a/core/crypto/rsa_test.go b/core/crypto/rsa_test.go index 69151b86c9..f4a7971a59 100644 --- a/core/crypto/rsa_test.go +++ b/core/crypto/rsa_test.go @@ -68,6 +68,44 @@ func TestRSASmallKey(t *testing.T) { } } +func TestRSABigKeyFailsToGenerate(t *testing.T) { + _, _, err := GenerateRSAKeyPair(maxRsaKeyBits*2, rand.Reader) + if err != ErrRsaKeyTooBig { + t.Fatal("should have refused to create too big RSA key") + } +} + +func TestRSABigKey(t *testing.T) { + // Make the global limit smaller for this test to run faster. + // Note we also change the limit below, but this is different + origSize := maxRsaKeyBits + maxRsaKeyBits = 2048 + defer func() { maxRsaKeyBits = origSize }() // + + maxRsaKeyBits *= 2 + badPriv, badPub, err := GenerateRSAKeyPair(maxRsaKeyBits, rand.Reader) + if err != nil { + t.Fatalf("should have succeeded, got: %s", err) + } + pubBytes, err := MarshalPublicKey(badPub) + if err != nil { + t.Fatal(err) + } + privBytes, err := MarshalPrivateKey(badPriv) + if err != nil { + t.Fatal(err) + } + maxRsaKeyBits /= 2 + _, err = UnmarshalPublicKey(pubBytes) + if err != ErrRsaKeyTooBig { + t.Fatal("should have refused to unmarshal a too big key") + } + _, err = UnmarshalPrivateKey(privBytes) + if err != ErrRsaKeyTooBig { + t.Fatal("should have refused to unmarshal a too big key") + } +} + func TestRSASignZero(t *testing.T) { priv, pub, err := GenerateRSAKeyPair(2048, rand.Reader) if err != nil { diff --git a/core/crypto/secp256k1.go b/core/crypto/secp256k1.go index 3b3aa6fe7e..27544a59f9 100644 --- a/core/crypto/secp256k1.go +++ b/core/crypto/secp256k1.go @@ -12,10 +12,10 @@ import ( "github.com/minio/sha256-simd" ) -// Secp256k1PrivateKey is an Secp256k1 private key +// Secp256k1PrivateKey is a Secp256k1 private key type Secp256k1PrivateKey secp256k1.PrivateKey -// Secp256k1PublicKey is an Secp256k1 public key +// Secp256k1PublicKey is a Secp256k1 public key type Secp256k1PublicKey secp256k1.PublicKey // GenerateSecp256k1Key generates a new Secp256k1 private and public key pair diff --git a/core/event/addrs.go b/core/event/addrs.go index 67026d1783..312a2fad56 100644 --- a/core/event/addrs.go +++ b/core/event/addrs.go @@ -59,7 +59,7 @@ type UpdatedAddress struct { // // In addition to the above, EvtLocalAddressesUpdated also contains the updated peer.PeerRecord // for the Current set of listen addresses, wrapped in a record.Envelope and signed by the Host's private key. -// This record can be shared with other peers to inform them of what we believe are our diallable addresses +// This record can be shared with other peers to inform them of what we believe are our diallable addresses // a secure and authenticated way. type EvtLocalAddressesUpdated struct { diff --git a/core/event/bus.go b/core/event/bus.go index 13e18e5356..1929f064d2 100644 --- a/core/event/bus.go +++ b/core/event/bus.go @@ -18,7 +18,7 @@ type CancelFunc = func() // subscriptions. type wildcardSubscriptionType interface{} -// WildcardSubscription is the type to subscribe to to receive all events +// WildcardSubscription is the type to subscribe to receive all events // emitted in the eventbus. var WildcardSubscription = new(wildcardSubscriptionType) diff --git a/core/event/dht.go b/core/event/dht.go index e01953f1d2..22e924e256 100644 --- a/core/event/dht.go +++ b/core/event/dht.go @@ -13,7 +13,7 @@ type RawJSON string // EXPERIMENTAL: this will likely be removed if/when the DHT event types are // hoisted to core, and the DHT event system is reconciled with the eventbus. type GenericDHTEvent struct { - // Type is the type of the DHT event that occured. + // Type is the type of the DHT event that occurred. Type string // Raw is the raw JSON representation of the event payload. diff --git a/core/event/network.go b/core/event/network.go index 37e9177d2f..37dd09ca9a 100644 --- a/core/event/network.go +++ b/core/event/network.go @@ -22,7 +22,7 @@ import ( // - It's possible to have _multiple_ connections to a given peer. // - Both libp2p and networks are asynchronous. // -// This means that all of the following situations are possible: +// This means that all the following situations are possible: // // A connection is cut and is re-established: // @@ -46,9 +46,9 @@ import ( // // Explanation: There were two connections and one was cut. This connection // might have been in active use but neither peer will observe a change in -// "connectedness". Peers should always make sure to re-try network requests. +// "connectedness". Peers should always make sure to retry network requests. type EvtPeerConnectednessChanged struct { - // Peer is the remote peer who's connectedness has changed. + // Peer is the remote peer whose connectedness has changed. Peer peer.ID // Connectedness is the new connectedness state. Connectedness network.Connectedness diff --git a/core/host/host.go b/core/host/host.go index e62be281f1..7990f7f456 100644 --- a/core/host/host.go +++ b/core/host/host.go @@ -47,7 +47,7 @@ type Host interface { // SetStreamHandler sets the protocol handler on the Host's Mux. // This is equivalent to: // host.Mux().SetHandler(proto, handler) - // (Threadsafe) + // (Thread-safe) SetStreamHandler(pid protocol.ID, handler network.StreamHandler) // SetStreamHandlerMatch sets the protocol handler on the Host's Mux @@ -61,7 +61,7 @@ type Host interface { // NewStream opens a new stream to given peer p, and writes a p2p/protocol // header with given ProtocolID. If there is no connection to p, attempts // to create one. If ProtocolID is "", writes no header. - // (Threadsafe) + // (Thread-safe) NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error) // Close shuts down the host, its Network, and services. diff --git a/core/metrics/bandwidth.go b/core/metrics/bandwidth.go index 3532bf5ee0..84360bd7c3 100644 --- a/core/metrics/bandwidth.go +++ b/core/metrics/bandwidth.go @@ -36,7 +36,7 @@ func (bwc *BandwidthCounter) LogSentMessage(size int64) { } // LogRecvMessage records the size of an incoming message -// without associating the bandwith to a specific peer or protocol. +// without associating the bandwidth to a specific peer or protocol. func (bwc *BandwidthCounter) LogRecvMessage(size int64) { bwc.totalIn.Mark(uint64(size)) } @@ -70,7 +70,7 @@ func (bwc *BandwidthCounter) GetBandwidthForPeer(p peer.ID) (out Stats) { } // GetBandwidthForProtocol returns a Stats struct with bandwidth metrics associated with the given protocol.ID. -// The metrics returned include all traffic sent / recieved for the protocol, regardless of which peers were +// The metrics returned include all traffic sent / received for the protocol, regardless of which peers were // involved. func (bwc *BandwidthCounter) GetBandwidthForProtocol(proto protocol.ID) (out Stats) { inSnap := bwc.protocolIn.Get(string(proto)).Snapshot() @@ -84,7 +84,7 @@ func (bwc *BandwidthCounter) GetBandwidthForProtocol(proto protocol.ID) (out Sta } } -// GetBandwidthTotals returns a Stats struct with bandwidth metrics for all data sent / recieved by the +// GetBandwidthTotals returns a Stats struct with bandwidth metrics for all data sent / received by the // local peer, regardless of protocol or remote peer IDs. func (bwc *BandwidthCounter) GetBandwidthTotals() (out Stats) { inSnap := bwc.totalIn.Snapshot() diff --git a/core/network/errors.go b/core/network/errors.go index 2209ee2332..03bb90c266 100644 --- a/core/network/errors.go +++ b/core/network/errors.go @@ -28,6 +28,6 @@ var ErrTransientConn = errors.New("transient connection to peer") // exceed system resource limits. var ErrResourceLimitExceeded = temporaryError("resource limit exceeded") -// ErrResourceScopeClosed is returned when attemptig to reserve resources in a closed resource +// ErrResourceScopeClosed is returned when attempting to reserve resources in a closed resource // scope. var ErrResourceScopeClosed = errors.New("resource scope closed") diff --git a/core/network/mocks/mock_resource_scope_span.go b/core/network/mocks/mock_resource_scope_span.go new file mode 100644 index 0000000000..ba9a4245db --- /dev/null +++ b/core/network/mocks/mock_resource_scope_span.go @@ -0,0 +1,102 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/libp2p/go-libp2p/core/network (interfaces: ResourceScopeSpan) + +// Package mocknetwork is a generated GoMock package. +package mocknetwork + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + network "github.com/libp2p/go-libp2p/core/network" +) + +// MockResourceScopeSpan is a mock of ResourceScopeSpan interface. +type MockResourceScopeSpan struct { + ctrl *gomock.Controller + recorder *MockResourceScopeSpanMockRecorder +} + +// MockResourceScopeSpanMockRecorder is the mock recorder for MockResourceScopeSpan. +type MockResourceScopeSpanMockRecorder struct { + mock *MockResourceScopeSpan +} + +// NewMockResourceScopeSpan creates a new mock instance. +func NewMockResourceScopeSpan(ctrl *gomock.Controller) *MockResourceScopeSpan { + mock := &MockResourceScopeSpan{ctrl: ctrl} + mock.recorder = &MockResourceScopeSpanMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockResourceScopeSpan) EXPECT() *MockResourceScopeSpanMockRecorder { + return m.recorder +} + +// BeginSpan mocks base method. +func (m *MockResourceScopeSpan) BeginSpan() (network.ResourceScopeSpan, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BeginSpan") + ret0, _ := ret[0].(network.ResourceScopeSpan) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BeginSpan indicates an expected call of BeginSpan. +func (mr *MockResourceScopeSpanMockRecorder) BeginSpan() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginSpan", reflect.TypeOf((*MockResourceScopeSpan)(nil).BeginSpan)) +} + +// Done mocks base method. +func (m *MockResourceScopeSpan) Done() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Done") +} + +// Done indicates an expected call of Done. +func (mr *MockResourceScopeSpanMockRecorder) Done() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Done", reflect.TypeOf((*MockResourceScopeSpan)(nil).Done)) +} + +// ReleaseMemory mocks base method. +func (m *MockResourceScopeSpan) ReleaseMemory(arg0 int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "ReleaseMemory", arg0) +} + +// ReleaseMemory indicates an expected call of ReleaseMemory. +func (mr *MockResourceScopeSpanMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReleaseMemory), arg0) +} + +// ReserveMemory mocks base method. +func (m *MockResourceScopeSpan) ReserveMemory(arg0 int, arg1 byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReserveMemory", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReserveMemory indicates an expected call of ReserveMemory. +func (mr *MockResourceScopeSpanMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReserveMemory), arg0, arg1) +} + +// Stat mocks base method. +func (m *MockResourceScopeSpan) Stat() network.ScopeStat { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stat") + ret0, _ := ret[0].(network.ScopeStat) + return ret0 +} + +// Stat indicates an expected call of Stat. +func (mr *MockResourceScopeSpanMockRecorder) Stat() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockResourceScopeSpan)(nil).Stat)) +} diff --git a/core/network/mocks/network.go b/core/network/mocks/network.go index 5408f0fc33..6fe8e91736 100644 --- a/core/network/mocks/network.go +++ b/core/network/mocks/network.go @@ -5,3 +5,4 @@ package mocknetwork //go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_stream_management_scope.go github.com/libp2p/go-libp2p/core/network StreamManagementScope" //go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_peer_scope.go github.com/libp2p/go-libp2p/core/network PeerScope" //go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_protocol_scope.go github.com/libp2p/go-libp2p/core/network ProtocolScope" +//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_resource_scope_span.go github.com/libp2p/go-libp2p/core/network ResourceScopeSpan" diff --git a/core/network/network.go b/core/network/network.go index 0beaac0f71..66b0a1cd34 100644 --- a/core/network/network.go +++ b/core/network/network.go @@ -34,10 +34,12 @@ const ( DirOutbound ) +const unrecognized = "(unrecognized)" + func (d Direction) String() string { str := [...]string{"Unknown", "Inbound", "Outbound"} if d < 0 || int(d) >= len(str) { - return "(unrecognized)" + return unrecognized } return str[d] } @@ -64,7 +66,7 @@ const ( func (c Connectedness) String() string { str := [...]string{"NotConnected", "Connected", "CanConnect", "CannotConnect"} if c < 0 || int(c) >= len(str) { - return "(unrecognized)" + return unrecognized } return str[c] } @@ -91,7 +93,7 @@ const ( func (r Reachability) String() string { str := [...]string{"Unknown", "Public", "Private"} if r < 0 || int(r) >= len(str) { - return "(unrecognized)" + return unrecognized } return str[r] } @@ -128,7 +130,7 @@ type Network interface { io.Closer // SetStreamHandler sets the handler for new streams opened by the - // remote side. This operation is threadsafe. + // remote side. This operation is thread-safe. SetStreamHandler(StreamHandler) // NewStream returns a new stream to given peer p. @@ -184,3 +186,13 @@ type Dialer interface { Notify(Notifiee) StopNotify(Notifiee) } + +// AddrDelay provides an address along with the delay after which the address +// should be dialed +type AddrDelay struct { + Addr ma.Multiaddr + Delay time.Duration +} + +// DialRanker provides a schedule of dialing the provided addresses +type DialRanker func([]ma.Multiaddr) []AddrDelay diff --git a/core/network/rcmgr.go b/core/network/rcmgr.go index 524a28a8c4..992a3875c9 100644 --- a/core/network/rcmgr.go +++ b/core/network/rcmgr.go @@ -28,7 +28,7 @@ import ( // +---------------------------> Stream // // The basic resources accounted by the ResourceManager include memory, streams, connections, -// and file descriptors. These account for both space and time used by +// and file descriptors. These account for both space and time used by // the stack, as each resource has a direct effect on the system // availability and performance. // @@ -69,7 +69,7 @@ import ( // service scope using the ResourceManager interface. // - Applications that want to account for their network resource usage can reserve memory, // typically using a span, directly in the System or a Service scope; they can also -// opt to use appropriate steam scopes for streams that they create or own. +// opt to use appropriate stream scopes for streams that they create or own. // // User Serviceable Parts: the user has the option to specify their own implementation of the // interface. We provide a canonical implementation in the go-libp2p-resource-manager package. @@ -77,8 +77,7 @@ import ( // or dynamic. // // WARNING The ResourceManager interface is considered experimental and subject to change -// -// in subsequent releases. +// in subsequent releases. type ResourceManager interface { ResourceScopeViewer @@ -102,7 +101,7 @@ type ResourceManager interface { // ResourceScopeViewer is a mixin interface providing view methods for accessing top level // scopes. type ResourceScopeViewer interface { - // ViewSystem views the system wide resource scope. + // ViewSystem views the system-wide resource scope. // The system scope is the top level scope that accounts for global // resource usage at all levels of the system. This scope constrains all // other scopes and institutes global hard limits. @@ -110,7 +109,7 @@ type ResourceScopeViewer interface { // ViewTransient views the transient (DMZ) resource scope. // The transient scope accounts for resources that are in the process of - // full establishment. For instance, a new connection prior to the + // full establishment. For instance, a new connection prior to the // handshake does not belong to any peer, but it still needs to be // constrained as this opens an avenue for attacks in transient resource // usage. Similarly, a stream that has not negotiated a protocol yet is @@ -134,7 +133,7 @@ const ( // Reservation PriorityMedium is a reservation priority that indicates a reservation if the scope // memory utilization is at 60% or less. ReservationPriorityMedium uint8 = 152 - // ReservationPriorityHigh is a reservation prioirity that indicates a reservation if the scope + // ReservationPriorityHigh is a reservation priority that indicates a reservation if the scope // memory utilization is at 80% or less. ReservationPriorityHigh uint8 = 203 // ReservationPriorityAlways is a reservation priority that indicates a reservation if there is @@ -155,7 +154,7 @@ type ResourceScope interface { // For instance, a muxer growing a window buffer will use a low priority and only grow the buffer // if there is no memory pressure in the system. // - // The are 4 predefined priority levels, Low, Medium, High and Always, + // There are 4 predefined priority levels, Low, Medium, High and Always, // capturing common patterns, but the user is free to use any granularity applicable to his case. ReserveMemory(size int, prio uint8) error @@ -218,7 +217,7 @@ type ConnManagementScope interface { ResourceScopeSpan // PeerScope returns the peer scope associated with this connection. - // It returns nil if the connection is not yet asociated with any peer. + // It returns nil if the connection is not yet associated with any peer. PeerScope() PeerScope // SetPeer sets the peer for a previously unassociated connection diff --git a/core/peer/addrinfo.go b/core/peer/addrinfo.go index b479df9e06..fba4cfd0eb 100644 --- a/core/peer/addrinfo.go +++ b/core/peer/addrinfo.go @@ -47,7 +47,7 @@ func AddrInfosFromP2pAddrs(maddrs ...ma.Multiaddr) ([]AddrInfo, error) { // SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID. // // * Returns a nil transport if the address only contains a /p2p part. -// * Returns a empty peer ID if the address doesn't contain a /p2p part. +// * Returns an empty peer ID if the address doesn't contain a /p2p part. func SplitAddr(m ma.Multiaddr) (transport ma.Multiaddr, id ID) { if m == nil { return nil, "" diff --git a/core/peer/peer.go b/core/peer/peer.go index 7bd4f8d245..f7f649f24d 100644 --- a/core/peer/peer.go +++ b/core/peer/peer.go @@ -88,7 +88,7 @@ func (id ID) MatchesPublicKey(pk ic.PubKey) bool { // ExtractPublicKey attempts to extract the public key from an ID. // -// This method returns ErrNoPublicKey if the peer ID looks valid but it can't extract +// This method returns ErrNoPublicKey if the peer ID looks valid, but it can't extract // the public key. func (id ID) ExtractPublicKey() (ic.PubKey, error) { decoded, err := mh.Decode([]byte(id)) diff --git a/core/peer/record.go b/core/peer/record.go index 0fc7e552db..49d89e146f 100644 --- a/core/peer/record.go +++ b/core/peer/record.go @@ -22,10 +22,10 @@ func init() { record.RegisterType(&PeerRecord{}) } -// PeerRecordEnvelopeDomain is the domain string used for peer records contained in a Envelope. +// PeerRecordEnvelopeDomain is the domain string used for peer records contained in an Envelope. const PeerRecordEnvelopeDomain = "libp2p-peer-record" -// PeerRecordEnvelopePayloadType is the type hint used to identify peer records in a Envelope. +// PeerRecordEnvelopePayloadType is the type hint used to identify peer records in an Envelope. // Defined in https://github.com/multiformats/multicodec/blob/master/table.csv // with name "libp2p-peer-record". var PeerRecordEnvelopePayloadType = []byte{0x03, 0x01} @@ -58,7 +58,7 @@ var PeerRecordEnvelopePayloadType = []byte{0x03, 0x01} // routing.Envelope, and PeerRecord implements the routing.Record interface // to facilitate this. // -// To share a PeerRecord, first call Sign to wrap the record in a Envelope +// To share a PeerRecord, first call Sign to wrap the record in an Envelope // and sign it with the local peer's private key: // // rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} diff --git a/core/peerstore/peerstore.go b/core/peerstore/peerstore.go index b63582afe6..4c9227f811 100644 --- a/core/peerstore/peerstore.go +++ b/core/peerstore/peerstore.go @@ -23,7 +23,7 @@ var ( // AddressTTL is the expiration time of addresses. AddressTTL = time.Hour - // TempAddrTTL is the ttl used for a short lived address. + // TempAddrTTL is the ttl used for a short-lived address. TempAddrTTL = time.Minute * 2 // RecentlyConnectedAddrTTL is used when we recently connected to a peer. @@ -46,7 +46,7 @@ const ( ConnectedAddrTTL ) -// Peerstore provides a threadsafe store of Peer related +// Peerstore provides a thread-safe store of Peer related // information. type Peerstore interface { io.Closer @@ -62,7 +62,7 @@ type Peerstore interface { // that peer, useful to other services. PeerInfo(peer.ID) peer.AddrInfo - // Peers returns all of the peer IDs stored across all inner stores. + // Peers returns all the peer IDs stored across all inner stores. Peers() peer.IDSlice } @@ -116,7 +116,7 @@ type AddrBook interface { // ClearAddresses removes all previously stored addresses. ClearAddrs(p peer.ID) - // PeersWithAddrs returns all of the peer IDs stored in the AddrBook. + // PeersWithAddrs returns all the peer IDs stored in the AddrBook. PeersWithAddrs() peer.IDSlice } @@ -174,7 +174,7 @@ type CertifiedAddrBook interface { // added via ConsumePeerRecord. ConsumePeerRecord(s *record.Envelope, ttl time.Duration) (accepted bool, err error) - // GetPeerRecord returns a Envelope containing a PeerRecord for the + // GetPeerRecord returns an Envelope containing a PeerRecord for the // given peer id, if one exists. // Returns nil if no signed PeerRecord exists for the peer. GetPeerRecord(p peer.ID) *record.Envelope diff --git a/core/pnet/codec.go b/core/pnet/codec.go index e741aba995..2ff1e7628c 100644 --- a/core/pnet/codec.go +++ b/core/pnet/codec.go @@ -31,7 +31,7 @@ func expectHeader(r *bufio.Reader, expected []byte) error { return err } if !bytes.Equal(header, expected) { - return fmt.Errorf("expected file header %s, got: %s", pathPSKv1, header) + return fmt.Errorf("expected file header %s, got: %s", expected, header) } return nil } diff --git a/core/record/envelope.go b/core/record/envelope.go index 6643c9a655..2ad01718e3 100644 --- a/core/record/envelope.go +++ b/core/record/envelope.go @@ -87,7 +87,7 @@ func Seal(rec Record, privateKey crypto.PrivKey) (*Envelope, error) { // ConsumeEnvelope unmarshals a serialized Envelope and validates its // signature using the provided 'domain' string. If validation fails, an error -// is returned, along with the unmarshalled envelope so it can be inspected. +// is returned, along with the unmarshalled envelope, so it can be inspected. // // On success, ConsumeEnvelope returns the Envelope itself, as well as the inner payload, // unmarshalled into a concrete Record type. The actual type of the returned Record depends @@ -106,11 +106,6 @@ func Seal(rec Record, privateKey crypto.PrivKey) (*Envelope, error) { // doSomethingWithPeerRecord(peerRec) // } // -// Important: you MUST check the error value before using the returned Envelope. In some error -// cases, including when the envelope signature is invalid, both the Envelope and an error will -// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, -// you must not assume that any non-nil Envelope returned from this function is valid. -// // If the Envelope signature is valid, but no Record type is registered for the Envelope's // PayloadType, ErrPayloadTypeNotRegistered will be returned, along with the Envelope and // a nil Record. @@ -122,19 +117,19 @@ func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record err = e.validate(domain) if err != nil { - return e, nil, fmt.Errorf("failed to validate envelope: %w", err) + return nil, nil, fmt.Errorf("failed to validate envelope: %w", err) } rec, err = e.Record() if err != nil { - return e, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) + return nil, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) } return e, rec, nil } // ConsumeTypedEnvelope unmarshals a serialized Envelope and validates its // signature. If validation fails, an error is returned, along with the unmarshalled -// envelope so it can be inspected. +// envelope, so it can be inspected. // // Unlike ConsumeEnvelope, ConsumeTypedEnvelope does not try to automatically determine // the type of Record to unmarshal the Envelope's payload into. Instead, the caller provides @@ -194,7 +189,7 @@ func UnmarshalEnvelope(data []byte) (*Envelope, error) { } // Marshal returns a byte slice containing a serialized protobuf representation -// of a Envelope. +// of an Envelope. func (e *Envelope) Marshal() (res []byte, err error) { defer func() { catch.HandlePanic(recover(), &err, "libp2p envelope marshal") }() key, err := crypto.PublicKeyToProto(e.PublicKey) @@ -277,7 +272,7 @@ func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, er fields = [][]byte{[]byte(domain), payloadType, payload} // fields are prefixed with their length as an unsigned varint. we - // compute the lengths before allocating the sig buffer so we know how + // compute the lengths before allocating the sig buffer, so we know how // much space to add for the lengths flen = make([][]byte, len(fields)) size = 0 diff --git a/core/record/record.go b/core/record/record.go index 704227f2a9..9b98f04f52 100644 --- a/core/record/record.go +++ b/core/record/record.go @@ -39,7 +39,7 @@ type Record interface { // (see https://github.com/multiformats/multicodec). // When a Record is put into an Envelope (see record.Seal), the Codec value will be used // as the Envelope's PayloadType. When the Envelope is later unsealed, the PayloadType - // will be used to lookup the correct Record type to unmarshal the Envelope payload into. + // will be used to look up the correct Record type to unmarshal the Envelope payload into. Codec() []byte // MarshalRecord converts a Record instance to a []byte, so that it can be used as an diff --git a/core/routing/query.go b/core/routing/query.go index 72791b5274..a99eccaef0 100644 --- a/core/routing/query.go +++ b/core/routing/query.go @@ -104,7 +104,7 @@ func PublishQueryEvent(ctx context.Context, ev *QueryEvent) { } // SubscribesToQueryEvents returns true if the context subscribes to query -// events. If this function returns falls, calling `PublishQueryEvent` on the +// events. If this function returns false, calling `PublishQueryEvent` on the // context will be a no-op. func SubscribesToQueryEvents(ctx context.Context) bool { return ctx.Value(routingQueryKey{}) != nil diff --git a/core/routing/routing.go b/core/routing/routing.go index 07437b5dff..e1d47451d6 100644 --- a/core/routing/routing.go +++ b/core/routing/routing.go @@ -55,7 +55,7 @@ type ValueStore interface { GetValue(context.Context, string, ...Option) ([]byte, error) // SearchValue searches for better and better values from this value - // store corresponding to the given Key. By default implementations must + // store corresponding to the given Key. By default, implementations must // stop the search after a good value is found. A 'good' value is a value // that would be returned from GetValue. // diff --git a/core/sec/insecure/insecure.go b/core/sec/insecure/insecure.go index 9ed20f093e..9d4fe11792 100644 --- a/core/sec/insecure/insecure.go +++ b/core/sec/insecure/insecure.go @@ -1,4 +1,4 @@ -// Package insecure provides an insecure, unencrypted implementation of the the SecureConn and SecureTransport interfaces. +// Package insecure provides an insecure, unencrypted implementation of the SecureConn and SecureTransport interfaces. // // Recommended only for testing and other non-production usage. package insecure diff --git a/core/test/mockclock.go b/core/test/mockclock.go index 1ed7250332..4916465586 100644 --- a/core/test/mockclock.go +++ b/core/test/mockclock.go @@ -50,6 +50,14 @@ func NewMockClock() *MockClock { return &MockClock{now: time.Unix(0, 0), advanceBySem: make(chan struct{}, 1)} } +// InstantTimer implements a timer that triggers at a fixed instant in time as opposed to after a +// fixed duration from the moment of creation/reset. +// +// In test environments, when using a Timer which fires after a duration, there is a race between +// the goroutine moving time forward using `clock.Advanceby` and the goroutine resetting the +// timer by doing `timer.Reset(desiredInstant.Sub(time.Now()))`. The value of +// `desiredInstance.sub(time.Now())` is different depending on whether `clock.AdvanceBy` finishes +// before or after the timer reset. func (c *MockClock) InstantTimer(when time.Time) *mockInstantTimer { c.mu.Lock() defer c.mu.Unlock() diff --git a/core/transport/transport.go b/core/transport/transport.go index 859c6d6088..89a9608d41 100644 --- a/core/transport/transport.go +++ b/core/transport/transport.go @@ -52,7 +52,7 @@ type CapableConn interface { // For a conceptual overview, see https://docs.libp2p.io/concepts/transport/ type Transport interface { // Dial dials a remote peer. It should try to reuse local listener - // addresses if possible but it may choose not to. + // addresses if possible, but it may choose not to. Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (CapableConn, error) // CanDial returns true if this transport knows how to dial the given diff --git a/dashboards/README.md b/dashboards/README.md index b275c78aa7..6080dc03f3 100644 --- a/dashboards/README.md +++ b/dashboards/README.md @@ -3,4 +3,37 @@ This directory contains prebuilt dashboards (provided as JSON files) for various components. For steps on how to import and use them [please read the official Grafana documentation.](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard) -More metrics and instrumentation is being added, if you'd like to follow along or contribute, [please see this tracking issue](https://github.com/libp2p/go-libp2p/issues/1356). \ No newline at end of file +## Using locally + +For local development and debugging, it can be useful to spin up a local Prometheus and Grafana instance. + +To expose metrics, we first need to expose a metrics collection endpoint. Add this to your code: + +```go +import "github.com/prometheus/client_golang/prometheus/promhttp" + +go func() { + http.Handle("/debug/metrics/prometheus", promhttp.Handler()) + log.Fatal(http.ListenAndServe(":5001", nil)) +}() +``` + +This exposes a metrics collection endpoint at http://localhost:5001/debug/metrics/prometheus. Note that this is the same endpoint that [Kubo](https://github.com/ipfs/kubo) uses, so if you want to gather metrics from Kubo, you can skip this step. + +On macOS: +```bash +docker compose -f docker-compose.base.yml up +``` +On Linux, dashboards can be inspected locally by running: +```bash +docker compose -f docker-compose.base.yml -f docker-compose-linux.yml up +``` + +and opening Grafana at http://localhost:3000. + + +### Making Dashboards usable with Provisioning + +The following section is only relevant for creators of dashboards. + +Due to a bug in Grafana, it's not possible to provision dashboards shared for external use directly. We need to apply the workaround described in https://github.com/grafana/grafana/issues/10786#issuecomment-568788499 (adding a few lines in the dashboard JSON file). diff --git a/dashboards/autonat/autonat.json b/dashboards/autonat/autonat.json index a7aec1fac9..4a14de8055 100644 --- a/dashboards/autonat/autonat.json +++ b/dashboards/autonat/autonat.json @@ -691,6 +691,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { diff --git a/dashboards/autorelay/autorelay.json b/dashboards/autorelay/autorelay.json index 6c4bd676a1..9b558ee6b3 100644 --- a/dashboards/autorelay/autorelay.json +++ b/dashboards/autorelay/autorelay.json @@ -1034,6 +1034,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { diff --git a/dashboards/dashboard.yml b/dashboards/dashboard.yml new file mode 100644 index 0000000000..b0a81133f3 --- /dev/null +++ b/dashboards/dashboard.yml @@ -0,0 +1,12 @@ +apiVersion: 1 + +providers: + - name: "libp2p dashboard provider" + orgId: 1 + type: file + disableDeletion: false + updateIntervalSeconds: 10 + allowUiUpdates: false + options: + path: /var/lib/grafana/dashboards + foldersFromFilesStructure: true diff --git a/dashboards/datasources.yml b/dashboards/datasources.yml new file mode 100644 index 0000000000..ed47ec11a1 --- /dev/null +++ b/dashboards/datasources.yml @@ -0,0 +1,13 @@ +apiVersion: 1 + +deleteDatasources: + - name: Prometheus + orgId: 1 + +datasources: + - name: Prometheus + orgId: 1 + type: prometheus + access: proxy + url: http://prometheus:9090 + editable: false diff --git a/dashboards/docker-compose-linux.yml b/dashboards/docker-compose-linux.yml new file mode 100644 index 0000000000..da9293249e --- /dev/null +++ b/dashboards/docker-compose-linux.yml @@ -0,0 +1,12 @@ +version: "3.7" +services: + prometheus: + network_mode: "host" + extra_hosts: + # define a host.docker.internal alias, so we can use the same prometheus.yml on Linux and macOS + - "host.docker.internal:127.0.0.1" + grafana: + network_mode: "host" + extra_hosts: + # define a prometheus alias, so we can use the same datasources.yml on Linux and macOS + - "prometheus:127.0.0.1" diff --git a/dashboards/docker-compose.base.yml b/dashboards/docker-compose.base.yml new file mode 100644 index 0000000000..4c87d284ea --- /dev/null +++ b/dashboards/docker-compose.base.yml @@ -0,0 +1,28 @@ +version: "3.7" +services: + prometheus: + image: prom/prometheus:latest + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + grafana: + image: grafana/grafana:latest + depends_on: + - prometheus + ports: + - "3000:3000" + environment: + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + volumes: + - ./dashboard.yml:/etc/grafana/provisioning/dashboards/main.yml + - ./datasources.yml:/etc/grafana/provisioning/datasources/prom.yml + - ./autonat/autonat.json:/var/lib/grafana/dashboards/autonat.json + - ./autorelay/autorelay.json:/var/lib/grafana/dashboards/autorelay.json + - ./eventbus/eventbus.json:/var/lib/grafana/dashboards/eventbus.json + - ./holepunch/holepunch.json:/var/lib/grafana/dashboards/holepunch.json + - ./identify/identify.json:/var/lib/grafana/dashboards/identify.json + - ./relaysvc/relaysvc.json:/var/lib/grafana/dashboards/relaysvc.json + - ./swarm/swarm.json:/var/lib/grafana/dashboards/swarm.json diff --git a/dashboards/eventbus/eventbus.json b/dashboards/eventbus/eventbus.json index b53211c152..24b7e22845 100644 --- a/dashboards/eventbus/eventbus.json +++ b/dashboards/eventbus/eventbus.json @@ -515,6 +515,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { diff --git a/dashboards/holepunch/holepunch.json b/dashboards/holepunch/holepunch.json new file mode 100644 index 0000000000..ba20951500 --- /dev/null +++ b/dashboards/holepunch/holepunch.json @@ -0,0 +1,1136 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.3.6" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "DCUtR Initiator", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 19, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (outcome) (increase(libp2p_holepunch_address_outcomes_total {side=\"initiator\", transport=\"tcp\", outcome=~\"success|failed\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: TCP", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 20, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (increase(libp2p_holepunch_address_outcomes_total {side=\"initiator\", transport=~\"quic|quic-v1\", outcome=~\"success|failed\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: QUIC", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "no_suitable_address" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 6, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (increase(libp2p_holepunch_outcomes_total{side=\"initiator\",instance=~\"$instance\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: Total", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_holepunch_direct_dials_total{instance=~\"$instance\"}[$__rate_interval])", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Direct dials", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "no_suitable_address" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (libp2p_holepunch_outcomes_total{side=\"initiator\",instance=~\"$instance\"}) - (sum by (outcome)(libp2p_holepunch_outcomes_total{side=\"initiator\",instance=~\"$instance\"} offset $__interval) or vector(0))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 14, + "panels": [], + "title": "DCUtR Receiver", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 18, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (increase(libp2p_holepunch_address_outcomes_total {side=\"receiver\", transport=~\"quic|quic-v1\", outcome=~\"success|failed\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: QUIC ", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 21, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (increase(libp2p_holepunch_address_outcomes_total {side=\"receiver\", transport=\"tcp\", outcome=~\"success|failed\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: TCP", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "no_suitable_address" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 34 + }, + "id": 17, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum by (outcome) (increase(libp2p_holepunch_outcomes_total{side=\"receiver\",instance=~\"$instance\"}[$__range]))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches: Total", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "no_suitable_address" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 34 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "(sum by (outcome) (libp2p_holepunch_outcomes_total{side=\"receiver\",instance=~\"$instance\"})) - (sum by (outcome)(libp2p_holepunch_outcomes_total{side=\"receiver\",instance=~\"$instance\"} offset $__interval) or vector(0))", + "legendFormat": "{{outcome}}", + "range": true, + "refId": "A" + } + ], + "title": "Hole punches", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": {}, + "definition": "label_values(instance)", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "instance", + "options": [], + "query": { + "query": "label_values(instance)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "libp2p Hole Punches", + "uid": "Ao24vOBVk", + "version": 6, + "weekStart": "" +} diff --git a/dashboards/identify/identify.json b/dashboards/identify/identify.json index e9c6efd0be..41d7823e88 100644 --- a/dashboards/identify/identify.json +++ b/dashboards/identify/identify.json @@ -838,6 +838,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { diff --git a/dashboards/prometheus.yml b/dashboards/prometheus.yml new file mode 100644 index 0000000000..f091718860 --- /dev/null +++ b/dashboards/prometheus.yml @@ -0,0 +1,30 @@ +global: + scrape_interval: 15s + scrape_timeout: 10s + evaluation_interval: 15s +alerting: + alertmanagers: + - scheme: http + timeout: 10s + api_version: v1 + static_configs: + - targets: [] +scrape_configs: +- job_name: prometheus + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /metrics + scheme: http + static_configs: + - targets: + - localhost:9090 +- job_name: libp2p + honor_timestamps: true + scrape_interval: 15s + scrape_timeout: 10s + metrics_path: /debug/metrics/prometheus + scheme: http + static_configs: + - targets: + - host.docker.internal:5001 diff --git a/dashboards/relaysvc/relaysvc.json b/dashboards/relaysvc/relaysvc.json index f2e7d69b0f..d70a8246b7 100644 --- a/dashboards/relaysvc/relaysvc.json +++ b/dashboards/relaysvc/relaysvc.json @@ -1190,6 +1190,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { diff --git a/dashboards/resource-manager/README.md b/dashboards/resource-manager/README.md index 6915c0e6d9..cded715679 100644 --- a/dashboards/resource-manager/README.md +++ b/dashboards/resource-manager/README.md @@ -5,29 +5,9 @@ import follow the Grafana docs [here](https://grafana.com/docs/grafana/latest/da ## Setup -To make sure you're emitting the correct metrics you'll have to register the -metrics with a Prometheus Registerer. For example: - -``` go -import ( - // ... - rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" - rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" - - "github.com/prometheus/client_golang/prometheus" -) - - func SetupResourceManager() (network.ResourceManager, error) { - rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer) - - str, err := rcmgrObs.NewStatsTraceReporter() - if err != nil { - return nil, err - } - - return rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str)) - } -``` +Metrics are enabled by default. By default, metrics will be sent to +`prometheus.DefaultRegisterer`. To use a different Registerer use the libp2p +option `libp2p.PrometheusRegisterer`. ## Updating Dashboard json diff --git a/dashboards/resource-manager/resource-manager.json b/dashboards/resource-manager/resource-manager.json index 16a8457206..8395b2a03a 100644 --- a/dashboards/resource-manager/resource-manager.json +++ b/dashboards/resource-manager/resource-manager.json @@ -1782,6 +1782,16 @@ "tags": [], "templating": { "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { @@ -1811,7 +1821,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Resource Manager", + "title": "libp2p Resource Manager", "uid": "MgmGIjjnj", "version": 1, "weekStart": "" diff --git a/dashboards/swarm/swarm.json b/dashboards/swarm/swarm.json index 84735c34cc..ec64784139 100644 --- a/dashboards/swarm/swarm.json +++ b/dashboards/swarm/swarm.json @@ -35,6 +35,18 @@ "name": "Prometheus", "version": "1.0.0" }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + }, { "type": "panel", "id": "timeseries", @@ -1224,7 +1236,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1450,7 +1463,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -2327,7 +2341,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -2553,13 +2568,733 @@ ], "title": "libp2p key types", "type": "piechart" - } - ], - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [ + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 75 + }, + "id": 40, + "panels": [], + "title": "Dial Prioritisation", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "<=300ms" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "<=500ms" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "<=750ms" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "<=50ms" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "<=10ms" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 76 + }, + "id": 38, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "percent" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.001\"}[$__range]))", + "format": "time_series", + "instant": false, + "legendFormat": "No delay", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.01\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.001\"}[$__range]))", + "hide": false, + "instant": false, + "legendFormat": "<=10ms", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.05\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.01\"}[$__range]))", + "hide": false, + "legendFormat": "<=50ms", + "range": true, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.3\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.05\"}[$__range]))", + "hide": false, + "legendFormat": "<=300ms", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.5\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.3\"}[$__range]))", + "hide": false, + "legendFormat": "<=500ms", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.75\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.5\"}[$__range]))", + "hide": false, + "legendFormat": "<=750ms", + "range": true, + "refId": "G" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"inf\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.75\"}[$__range]))", + "hide": false, + "legendFormat": ">750ms", + "range": true, + "refId": "H" + } + ], + "title": "Dial Ranking Delay", + "transformations": [], + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": ">=6" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "5" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "2" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "1" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "3" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "4" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 76 + }, + "id": 42, + "options": { + "displayLabels": [ + "percent", + "name" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "percent" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"0\"}[$__range])", + "legendFormat": "0", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"1\"}[$__range])", + "hide": false, + "legendFormat": "1", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"2\"}[$__range])", + "hide": false, + "legendFormat": "2", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"3\"}[$__range])", + "hide": false, + "legendFormat": "3", + "range": true, + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"4\"}[$__range])", + "hide": false, + "legendFormat": "4", + "range": true, + "refId": "E" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\"5\"}[$__range])", + "hide": false, + "legendFormat": "5", + "range": true, + "refId": "F" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "increase(libp2p_swarm_dials_per_peer_total{instance=~\"$instance\", outcome=\"success\", num_dials=\">=6\"}[$__range])", + "hide": false, + "legendFormat": ">=6", + "range": true, + "refId": "G" + } + ], + "title": "Dials per connection", + "type": "piechart" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 84 + }, + "id": 44, + "panels": [], + "title": "Black Hole Detection", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "fillOpacity": 76, + "lineWidth": 0, + "spanNulls": true + }, + "mappings": [ + { + "options": { + "0": { + "color": "blue", + "index": 0, + "text": "Probing" + }, + "1": { + "color": "green", + "index": 1, + "text": "Allowed" + }, + "2": { + "color": "purple", + "index": 2, + "text": "Blocked" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 85 + }, + "id": 46, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "always", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_swarm_black_hole_filter_state{instance=~\"$instance\"}", + "legendFormat": "{{instance}} {{name}}", + "range": true, + "refId": "A" + } + ], + "title": "Black Hole Filter State", + "type": "state-timeline" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "purple", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "0": { + "index": 0, + "text": "-" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 91 + }, + "id": 49, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_swarm_black_hole_filter_next_request_allowed_after{instance=~\"$instance\"}", + "legendFormat": "{{instance}}: {{name}}", + "range": true, + "refId": "A" + } + ], + "title": "Black Hole Filter Requests Till Next Probe", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 10, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "green", + "value": 5 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 91 + }, + "id": 47, + "options": { + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "libp2p_swarm_black_hole_filter_success_fraction{instance=~\"$instance\"} * 100", + "instant": true, + "legendFormat": "{{instance}} {{name}}", + "range": false, + "refId": "A" + } + ], + "title": "Black Hole Filter Success Percentage", + "type": "gauge" + } + ], + "refresh": false, + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "hide": 0, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, { "current": {}, "datasource": { @@ -2577,6 +3312,7 @@ "refId": "StandardVariableQuery" }, "refresh": 1, + "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" @@ -2584,13 +3320,13 @@ ] }, "time": { - "from": "now-15m", + "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "libp2p Swarm", "uid": "a15PyhO4z", - "version": 12, + "version": 7, "weekStart": "" } diff --git a/examples/chat-with-mdns/README.md b/examples/chat-with-mdns/README.md index 54ef979737..836fb7a7bb 100644 --- a/examples/chat-with-mdns/README.md +++ b/examples/chat-with-mdns/README.md @@ -75,7 +75,7 @@ register [Notifee interface](https://godoc.org/github.com/libp2p/go-libp2p/p2p/d Finally we open stream to the peers we found, as we find them ```go - peer := <-peerChan // will block untill we discover a peer + peer := <-peerChan // will block until we discover a peer fmt.Println("Found peer:", peer, ", connecting") if err := host.Connect(ctx, peer); err != nil { diff --git a/examples/chat-with-mdns/main.go b/examples/chat-with-mdns/main.go index fbe4773eff..57b89c2583 100644 --- a/examples/chat-with-mdns/main.go +++ b/examples/chat-with-mdns/main.go @@ -19,7 +19,7 @@ import ( func handleStream(stream network.Stream) { fmt.Println("Got a new stream!") - // Create a buffer stream for non blocking read and write. + // Create a buffer stream for non-blocking read and write. rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) go readData(rw) @@ -115,7 +115,7 @@ func main() { peerChan := initMDNS(host, cfg.RendezvousString) for { // allows multiple peers to join - peer := <-peerChan // will block untill we discover a peer + peer := <-peerChan // will block until we discover a peer fmt.Println("Found peer:", peer, ", connecting") if err := host.Connect(ctx, peer); err != nil { diff --git a/examples/chat-with-rendezvous/chat.go b/examples/chat-with-rendezvous/chat.go index 2b4262974f..5fc8d4e344 100644 --- a/examples/chat-with-rendezvous/chat.go +++ b/examples/chat-with-rendezvous/chat.go @@ -26,7 +26,7 @@ var logger = log.Logger("rendezvous") func handleStream(stream network.Stream) { logger.Info("Got a new stream!") - // Create a buffer stream for non blocking read and write. + // Create a buffer stream for non-blocking read and write. rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) go readData(rw) diff --git a/examples/chat/chat.go b/examples/chat/chat.go index 7276dfddae..cd1c2872ea 100644 --- a/examples/chat/chat.go +++ b/examples/chat/chat.go @@ -51,7 +51,7 @@ import ( func handleStream(s network.Stream) { log.Println("Got a new stream!") - // Create a buffer stream for non blocking read and write. + // Create a buffer stream for non-blocking read and write. rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) go readData(rw) @@ -227,7 +227,7 @@ func startPeerAndConnect(ctx context.Context, h host.Host, destination string) ( } log.Println("Established connection to destination") - // Create a buffered stream so that read and writes are non blocking. + // Create a buffered stream so that read and writes are non-blocking. rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s)) return rw, nil diff --git a/examples/echo/main.go b/examples/echo/main.go index fba00890c2..3bba896183 100644 --- a/examples/echo/main.go +++ b/examples/echo/main.go @@ -151,7 +151,7 @@ func runSender(ctx context.Context, ha host.Host, targetPeer string) { return } - // We have a peer ID and a targetAddr so we add it to the peerstore + // We have a peer ID and a targetAddr, so we add it to the peerstore // so LibP2P knows how to contact it ha.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL) diff --git a/examples/go.mod b/examples/go.mod index c38f9711cd..feb9b156a9 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -7,19 +7,20 @@ require ( github.com/google/uuid v1.3.0 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-log/v2 v2.5.1 - github.com/libp2p/go-libp2p v0.27.1 + github.com/libp2p/go-libp2p v0.29.0 github.com/libp2p/go-libp2p-kad-dht v0.20.1-0.20230209220319-6c2045abad23 - github.com/multiformats/go-multiaddr v0.9.0 + github.com/multiformats/go-multiaddr v0.10.1 + github.com/prometheus/client_golang v1.14.0 ) require ( - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/flynn/noise v1.0.0 // indirect @@ -29,11 +30,12 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect + github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huin/goupnp v1.1.0 // indirect + github.com/huin/goupnp v1.2.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-ipfs-util v0.0.2 // indirect github.com/ipfs/go-ipns v0.2.0 // indirect @@ -42,8 +44,8 @@ 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/klauspost/compress v1.16.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // 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/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -52,61 +54,59 @@ require ( github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.1.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.2.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/libp2p/go-reuseport v0.3.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.18 // 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.53 // 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.0 // 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.8.1 // indirect - github.com/multiformats/go-multihash v0.2.1 // 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.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // 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/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.2 // indirect + github.com/quic-go/quic-go v0.36.2 // indirect + github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.16.1 // indirect - go.uber.org/fx v1.19.2 // 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.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + golang.org/x/tools v0.11.0 // indirect google.golang.org/protobuf v1.30.0 // indirect - lukechampine.com/blake3 v1.1.7 // indirect - nhooyr.io/websocket v1.8.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 6016ca1341..5ac4751644 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -10,8 +10,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -38,9 +39,9 @@ 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.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +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/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= @@ -61,28 +62,11 @@ github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnX github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 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/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -102,8 +86,6 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev 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.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= @@ -127,14 +109,12 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= +github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -143,8 +123,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -154,10 +134,8 @@ 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 v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= 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= @@ -185,22 +163,18 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +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.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +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/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= @@ -212,16 +186,14 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/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.27.1 h1:k1u6RHsX3hqKnslDjsSgLNURxJ3O1atIZCY4gpMbbus= -github.com/libp2p/go-libp2p v0.27.1/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE= +github.com/libp2p/go-libp2p v0.29.0 h1:QduJ2XQr/Crg4EnloueWDL0Jj86N3Ezhyyj7XH+XwHI= +github.com/libp2p/go-libp2p v0.29.0/go.mod h1:iNKL7mEnZ9wAss+03IjAwM9ZAQXfVUAPUUmOACQfQ/g= 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-kad-dht v0.20.1-0.20230209220319-6c2045abad23 h1:VGjUg3I0gLugtjZKI4kzvPiptmfYhWHK6YGBI4ZI2Cs= @@ -233,34 +205,31 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN 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.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +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.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +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/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= 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-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/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/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.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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= @@ -269,14 +238,11 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn 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.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -289,8 +255,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.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= +github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= 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= @@ -299,14 +265,14 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g 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.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= -github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-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.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +github.com/multiformats/go-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= @@ -316,9 +282,9 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 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/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +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 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -338,8 +304,8 @@ github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= @@ -352,10 +318,10 @@ github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc8 github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= -github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= -github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.36.2 h1:ZX/UNQ4gvpCv2RmwdbA6lrRjF6EBm5yZ7TMoT4NQVrA= +github.com/quic-go/quic-go v0.36.2/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= +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= @@ -407,12 +373,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -429,12 +391,12 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +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.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -458,11 +420,11 @@ golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= 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= @@ -474,12 +436,11 @@ 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.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.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-20181011144130-49bb7cea24b1/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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -495,8 +456,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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= @@ -510,19 +471,16 @@ 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -534,22 +492,20 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.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-20191024005414-555d28b269f0/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= @@ -568,8 +524,8 @@ 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= 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= @@ -631,9 +587,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh 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.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +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= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/http-proxy/proxy.go b/examples/http-proxy/proxy.go index 53af9ecd53..27d9597870 100644 --- a/examples/http-proxy/proxy.go +++ b/examples/http-proxy/proxy.go @@ -135,7 +135,7 @@ func (p *ProxyService) Serve() { } // ServeHTTP implements the http.Handler interface. WARNING: This is the -// simplest approach to a proxy. Therefore we do not do any of the things +// simplest approach to a proxy. Therefore, we do not do any of the things // that should be done when implementing a reverse proxy (like handling // headers correctly). For how to do it properly, see: // https://golang.org/src/net/http/httputil/reverseproxy.go?s=3845:3920#L121 @@ -216,7 +216,7 @@ func addAddrToPeerstore(h host.Host, addr string) peer.ID { targetPeerAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", peerid)) targetAddr := ipfsaddr.Decapsulate(targetPeerAddr) - // We have a peer ID and a targetAddr so we add + // We have a peer ID and a targetAddr, so we add // it to the peerstore so LibP2P knows how to contact it h.Peerstore().AddAddr(peerid, targetAddr, peerstore.PermanentAddrTTL) return peerid diff --git a/examples/ipfs-camp-2019/go.mod b/examples/ipfs-camp-2019/go.mod index d4bd349673..2bcabeb209 100644 --- a/examples/ipfs-camp-2019/go.mod +++ b/examples/ipfs-camp-2019/go.mod @@ -4,20 +4,20 @@ go 1.19 require ( github.com/gogo/protobuf v1.3.2 - github.com/libp2p/go-libp2p v0.27.1 + github.com/libp2p/go-libp2p v0.28.0 github.com/libp2p/go-libp2p-kad-dht v0.21.0 github.com/libp2p/go-libp2p-pubsub v0.9.0 github.com/multiformats/go-multiaddr v0.9.0 ) require ( - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -28,13 +28,14 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect + github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.1.0 // 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-ipfs-util v0.0.2 // indirect @@ -45,8 +46,8 @@ 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/klauspost/compress v1.16.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -56,61 +57,60 @@ require ( github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.1.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.2.0 // indirect + github.com/libp2p/go-reuseport v0.3.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.18 // 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.53 // indirect + github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/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.8.1 // indirect - github.com/multiformats/go-multihash v0.2.1 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.2 // 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.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/opencontainers/runtime-spec v1.0.2 // 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/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.2 // indirect + github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.16.1 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.9.1 // indirect google.golang.org/protobuf v1.30.0 // indirect - lukechampine.com/blake3 v1.1.7 // indirect - nhooyr.io/websocket v1.8.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/examples/ipfs-camp-2019/go.sum b/examples/ipfs-camp-2019/go.sum index a173108b23..23a9792eb7 100644 --- a/examples/ipfs-camp-2019/go.sum +++ b/examples/ipfs-camp-2019/go.sum @@ -10,8 +10,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -38,9 +39,9 @@ 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.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +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/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= @@ -63,28 +64,11 @@ github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnX github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 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/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -104,8 +88,6 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev 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.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= @@ -129,14 +111,12 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -145,8 +125,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -158,10 +138,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= 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= @@ -189,22 +167,18 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +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/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= @@ -216,16 +190,14 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/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.27.1 h1:k1u6RHsX3hqKnslDjsSgLNURxJ3O1atIZCY4gpMbbus= -github.com/libp2p/go-libp2p v0.27.1/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE= +github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= +github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= 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-kad-dht v0.21.0 h1:J0Yd22VA+sk0CJRGMgtfHvLVIkZDyJ3AJGiljywIw5U= @@ -241,14 +213,12 @@ github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= 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.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +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.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= @@ -257,18 +227,17 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm 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-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/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/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.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/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= @@ -277,14 +246,11 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn 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.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -307,14 +273,14 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g 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.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= -github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-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.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= +github.com/multiformats/go-multihash v0.2.2/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= @@ -324,9 +290,9 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 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/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -346,8 +312,8 @@ github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= @@ -362,8 +328,8 @@ github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8G github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= -github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/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= @@ -417,10 +383,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -437,10 +399,10 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= +go.uber.org/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.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= @@ -487,7 +449,6 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -503,8 +464,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 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= @@ -518,19 +479,16 @@ 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -542,22 +500,20 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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-20191024005414-555d28b269f0/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= @@ -576,8 +532,8 @@ 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= @@ -639,9 +595,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh 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.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +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= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/libp2p-host/host.go b/examples/libp2p-host/host.go index 2103925fee..b1b6790aa1 100644 --- a/examples/libp2p-host/host.go +++ b/examples/libp2p-host/host.go @@ -22,7 +22,7 @@ func main() { func run() { // The context governs the lifetime of the libp2p node. - // Cancelling it will stop the the host. + // Cancelling it will stop the host. ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/examples/metrics-and-dashboards/README.md b/examples/metrics-and-dashboards/README.md new file mode 100644 index 0000000000..9218994d2e --- /dev/null +++ b/examples/metrics-and-dashboards/README.md @@ -0,0 +1,13 @@ +# Metrics and Dashboards + +An example to demonstrate using Prometheus and Grafana to view go-libp2p +metrics. Sets up a Prometheus server and Grafana server via Docker compose. A +small go-libp2p dummy application is included to emit metrics. + +Run it with: + +``` +docker compose -f ../../dashboards/docker-compose.base.yml -f ./compose.yml up +``` + +Go to http://localhost:3000/dashboards to see the dashboards. diff --git a/examples/metrics-and-dashboards/compose.yml b/examples/metrics-and-dashboards/compose.yml new file mode 100644 index 0000000000..fb10b4a81a --- /dev/null +++ b/examples/metrics-and-dashboards/compose.yml @@ -0,0 +1,15 @@ +services: + prometheus: + image: prom/prometheus:latest + ports: + - "9090:9090" + volumes: + - ../examples/metrics-and-dashboards/prometheus.yml:/etc/prometheus/prometheus.yml + go-libp2p-node: + build: + context: ../examples/metrics-and-dashboards/ + dockerfile: go-libp2p-node.Dockerfile + ports: + - 5001:5001 + expose: + - 5001 diff --git a/examples/metrics-and-dashboards/go-libp2p-node.Dockerfile b/examples/metrics-and-dashboards/go-libp2p-node.Dockerfile new file mode 100644 index 0000000000..bd044e088a --- /dev/null +++ b/examples/metrics-and-dashboards/go-libp2p-node.Dockerfile @@ -0,0 +1,7 @@ +FROM golang:alpine +WORKDIR /app +COPY ./main.go . +RUN go mod init example.com/m/v2 +RUN go mod tidy +RUN go build main.go +ENTRYPOINT [ "/app/main" ] diff --git a/examples/metrics-and-dashboards/main.go b/examples/metrics-and-dashboards/main.go new file mode 100644 index 0000000000..37eee4285a --- /dev/null +++ b/examples/metrics-and-dashboards/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "net/http" + "sync" + "time" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" +) + +const ClientCount = 32 + +func main() { + http.Handle("/metrics", promhttp.Handler()) + go func() { + http.Handle("/debug/metrics/prometheus", promhttp.Handler()) + log.Fatal(http.ListenAndServe(":5001", nil)) + }() + + rcmgr.MustRegisterWith(prometheus.DefaultRegisterer) + + str, err := rcmgr.NewStatsTraceReporter() + if err != nil { + log.Fatal(err) + } + + rmgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(str)) + if err != nil { + log.Fatal(err) + } + server, err := libp2p.New(libp2p.ResourceManager(rmgr)) + if err != nil { + log.Fatal(err) + } + + // Make a bunch of clients that all ping the server at various times + wg := sync.WaitGroup{} + for i := 0; i < ClientCount; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + time.Sleep(time.Duration(i%100) * 100 * time.Millisecond) + newClient(peer.AddrInfo{ + ID: server.ID(), + Addrs: server.Addrs(), + }, i) + }(i) + } + wg.Wait() +} + +func newClient(serverInfo peer.AddrInfo, pings int) { + // Sleep some random amount of time to spread out the clients so the graphs look more interesting + time.Sleep(time.Duration(rand.Intn(100)) * time.Second) + fmt.Println("Started client", pings) + + client, err := libp2p.New( + // We just want metrics from the server + libp2p.DisableMetrics(), + libp2p.NoListenAddrs, + ) + defer func() { + _ = client.Close() + }() + + if err != nil { + log.Fatal(err) + } + + client.Connect(context.Background(), serverInfo) + + p := ping.Ping(context.Background(), client, serverInfo.ID) + + pingSoFar := 0 + for pingSoFar < pings { + res := <-p + pingSoFar++ + if res.Error != nil { + log.Fatal(res.Error) + } + time.Sleep(5 * time.Second) + } +} diff --git a/examples/metrics-and-dashboards/prometheus.yml b/examples/metrics-and-dashboards/prometheus.yml new file mode 100644 index 0000000000..3f86ad0c26 --- /dev/null +++ b/examples/metrics-and-dashboards/prometheus.yml @@ -0,0 +1,16 @@ +global: + scrape_interval: 1m + +scrape_configs: + - job_name: "prometheus" + scrape_interval: 1m + static_configs: + - targets: ["localhost:9090"] + + - job_name: "node" + static_configs: + - targets: ["node-exporter:9100"] + - job_name: "go-libp2p" + metrics_path: /debug/metrics/prometheus + static_configs: + - targets: ["go-libp2p-node:5001"] diff --git a/examples/multipro/README.md b/examples/multipro/README.md index db032848fb..6fb0b2e967 100644 --- a/examples/multipro/README.md +++ b/examples/multipro/README.md @@ -1,7 +1,7 @@ # Protocol Multiplexing using rpc-style protobufs with libp2p This example shows how to use protobufs to encode and transmit information between libp2p hosts using libp2p Streams. -This example expects that you are already familiar with the [echo example](https://github.com/libp2p/go-libp2p-examples/tree/master/echo). +This example expects that you are already familiar with the [echo example](https://github.com/libp2p/go-libp2p/tree/master/examples/echo). ## Build diff --git a/examples/multipro/node.go b/examples/multipro/node.go index 5b58cb2e2a..55b63928a6 100644 --- a/examples/multipro/node.go +++ b/examples/multipro/node.go @@ -35,7 +35,7 @@ func NewNode(host host.Host, done chan bool) *Node { } // Authenticate incoming p2p message -// message: a protobufs go data object +// message: a protobuf go data object // data: common p2p message data func (n *Node) authenticateMessage(message proto.Message, data *p2p.MessageData) bool { // store a temp ref to signature and remove it from message data @@ -119,7 +119,7 @@ func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyD // helper method - generate message data shared between all node's p2p protocols // messageId: unique for requests, copied from request for responses func (n *Node) NewMessageData(messageId string, gossip bool) *p2p.MessageData { - // Add protobufs bin data for message author public key + // Add protobuf bin data for message author public key // this is useful for authenticating messages forwarded by a node authored by another node nodePubKey, err := crypto.MarshalPublicKey(n.Peerstore().PubKey(n.ID())) diff --git a/examples/pubsub/basic-chat-with-rendezvous/README.md b/examples/pubsub/basic-chat-with-rendezvous/README.md index 0a3c06caeb..d8008fef47 100644 --- a/examples/pubsub/basic-chat-with-rendezvous/README.md +++ b/examples/pubsub/basic-chat-with-rendezvous/README.md @@ -23,10 +23,10 @@ go build . ./chat ``` -To change the topic name, use the `-topic` flag: +To change the topic name, use the `-topicName` flag: ```shell -go run . -topic=adifferenttopic +go run . -topicName=adifferenttopic ``` Try opening several terminals, each running the app. When you type a message and hit enter in one, it diff --git a/examples/pubsub/basic-chat-with-rendezvous/go.mod b/examples/pubsub/basic-chat-with-rendezvous/go.mod index 56e1bc817f..f9cf1ec684 100644 --- a/examples/pubsub/basic-chat-with-rendezvous/go.mod +++ b/examples/pubsub/basic-chat-with-rendezvous/go.mod @@ -3,19 +3,19 @@ module github.com/libp2p/go-libp2p/examples/pubsub/chat go 1.19 require ( - github.com/libp2p/go-libp2p v0.27.1 + github.com/libp2p/go-libp2p v0.28.0 github.com/libp2p/go-libp2p-kad-dht v0.21.0 github.com/libp2p/go-libp2p-pubsub v0.9.0 ) require ( - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -27,13 +27,14 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect + github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.1.0 // 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-ipfs-util v0.0.2 // indirect @@ -44,8 +45,8 @@ 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/klauspost/compress v1.16.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -54,17 +55,17 @@ require ( github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.1.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.2.0 // indirect + github.com/libp2p/go-reuseport v0.3.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.18 // 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.53 // indirect + github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/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 @@ -72,43 +73,42 @@ require ( 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.8.1 // indirect - github.com/multiformats/go-multihash v0.2.1 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.2 // 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.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/opencontainers/runtime-spec v1.0.2 // 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/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 // indirect github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.2 // indirect + github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.16.1 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.9.1 // indirect google.golang.org/protobuf v1.30.0 // indirect - lukechampine.com/blake3 v1.1.7 // indirect - nhooyr.io/websocket v1.8.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/examples/pubsub/basic-chat-with-rendezvous/go.sum b/examples/pubsub/basic-chat-with-rendezvous/go.sum index 11235bbe3a..8a766f9e0d 100644 --- a/examples/pubsub/basic-chat-with-rendezvous/go.sum +++ b/examples/pubsub/basic-chat-with-rendezvous/go.sum @@ -10,8 +10,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -37,9 +38,9 @@ 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.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +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/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= @@ -61,28 +62,11 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 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/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -102,8 +86,6 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev 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.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= @@ -127,14 +109,12 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -143,8 +123,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -156,10 +136,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= 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= @@ -187,22 +165,17 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +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/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= @@ -212,16 +185,14 @@ 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/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.27.1 h1:k1u6RHsX3hqKnslDjsSgLNURxJ3O1atIZCY4gpMbbus= -github.com/libp2p/go-libp2p v0.27.1/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE= +github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= +github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= 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-kad-dht v0.21.0 h1:J0Yd22VA+sk0CJRGMgtfHvLVIkZDyJ3AJGiljywIw5U= @@ -235,31 +206,28 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN 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.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +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.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= 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-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/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/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.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/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= @@ -268,14 +236,11 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn 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.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -297,14 +262,14 @@ github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDu github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= 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.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +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.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= +github.com/multiformats/go-multihash v0.2.2/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= @@ -314,9 +279,9 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 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/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -336,8 +301,8 @@ github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= @@ -352,8 +317,8 @@ github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8G github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= -github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/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= @@ -405,10 +370,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -424,10 +385,10 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= +go.uber.org/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.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= @@ -474,7 +435,6 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -489,8 +449,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 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= @@ -504,19 +464,16 @@ 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -526,21 +483,19 @@ golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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-20191024005414-555d28b269f0/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= @@ -559,8 +514,8 @@ 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= @@ -609,7 +564,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= @@ -620,9 +574,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh 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.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +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= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/pubsub/chat/go.mod b/examples/pubsub/chat/go.mod index 9c34111912..11b1eb1026 100644 --- a/examples/pubsub/chat/go.mod +++ b/examples/pubsub/chat/go.mod @@ -4,19 +4,19 @@ go 1.19 require ( github.com/gdamore/tcell/v2 v2.5.2 - github.com/libp2p/go-libp2p v0.27.1 + github.com/libp2p/go-libp2p v0.28.0 github.com/libp2p/go-libp2p-pubsub v0.9.0 github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 ) require ( - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -29,37 +29,37 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect + github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.1.0 // indirect + github.com/huin/goupnp v1.2.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.16.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.1.0 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.2.0 // indirect + github.com/libp2p/go-reuseport v0.3.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.53 // indirect + github.com/miekg/dns v1.1.54 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/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 @@ -67,42 +67,41 @@ require ( 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.8.1 // indirect - github.com/multiformats/go-multihash v0.2.1 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.2 // 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.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/opencontainers/runtime-spec v1.0.2 // 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/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.2 // 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.2.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.16.1 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.9.1 // indirect google.golang.org/protobuf v1.30.0 // indirect - lukechampine.com/blake3 v1.1.7 // indirect - nhooyr.io/websocket v1.8.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/examples/pubsub/chat/go.sum b/examples/pubsub/chat/go.sum index f205264915..e9d38f17f3 100644 --- a/examples/pubsub/chat/go.sum +++ b/examples/pubsub/chat/go.sum @@ -10,8 +10,9 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -35,9 +36,9 @@ 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.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +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/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= @@ -59,28 +60,11 @@ github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt github.com/gdamore/tcell/v2 v2.5.2 h1:tKzG29kO9p2V++3oBY2W9zUjYu7IK1MENFeY/BzJSVY= github.com/gdamore/tcell/v2 v2.5.2/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= 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/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -97,42 +81,34 @@ 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.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 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/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.4.0/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= 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-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= @@ -148,20 +124,14 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/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/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= @@ -171,16 +141,14 @@ 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/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.27.1 h1:k1u6RHsX3hqKnslDjsSgLNURxJ3O1atIZCY4gpMbbus= -github.com/libp2p/go-libp2p v0.27.1/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE= +github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= +github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= 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.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s= @@ -188,14 +156,12 @@ github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7b 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.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +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.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= @@ -206,10 +172,9 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm 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-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -218,8 +183,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr 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.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/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= @@ -228,14 +193,10 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn 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.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/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= @@ -253,11 +214,11 @@ github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/e github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-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.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= +github.com/multiformats/go-multihash v0.2.2/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= @@ -265,9 +226,9 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 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/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -284,8 +245,8 @@ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= @@ -300,8 +261,8 @@ github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8G github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= -github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/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/tview v0.0.0-20220307222120-9994674d60a8 h1:xe+mmCnDN82KhC010l3NfYlA8ZbOuzbXAzSYBa6wbMc= @@ -348,10 +309,6 @@ 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -361,10 +318,10 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= 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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= +go.uber.org/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.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= @@ -409,7 +366,6 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -424,8 +380,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 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= @@ -439,19 +395,16 @@ 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -464,26 +417,24 @@ golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.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-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 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.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.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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-20191024005414-555d28b269f0/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= @@ -500,8 +451,8 @@ 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= @@ -535,7 +486,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= @@ -544,9 +494,7 @@ 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.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +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= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/pubsub/chat/ui.go b/examples/pubsub/chat/ui.go index 51725bd1bb..413b6d3989 100644 --- a/examples/pubsub/chat/ui.go +++ b/examples/pubsub/chat/ui.go @@ -138,7 +138,7 @@ func (ui *ChatUI) displayChatMessage(cm *ChatMessage) { fmt.Fprintf(ui.msgW, "%s %s\n", prompt, cm.Message) } -// displaySelfMessage writes a message from ourself to the message window, +// displaySelfMessage writes a message from ourselves to the message window, // with our nick highlighted in yellow. func (ui *ChatUI) displaySelfMessage(msg string) { prompt := withColor("yellow", fmt.Sprintf("<%s>:", ui.cr.nick)) diff --git a/examples/relay/main.go b/examples/relay/main.go index 1a9ebd8766..e8fa8b7ba0 100644 --- a/examples/relay/main.go +++ b/examples/relay/main.go @@ -67,7 +67,7 @@ func run() { return } - // Configure the host to offer the ciruit relay service. + // Configure the host to offer the circuit relay service. // Any host that is directly dialable in the network (or on the internet) // can offer a circuit relay service, this isn't just the job of // "dedicated" relay services. diff --git a/go.mod b/go.mod index 8530037f60..3696cdd4ac 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.19 retract v0.26.1 // Tag was applied incorrectly due to a bug in the release workflow. require ( - github.com/benbjohnson/clock v1.3.0 + github.com/benbjohnson/clock v1.3.5 github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/flynn/noise v1.0.0 github.com/golang/mock v1.6.0 github.com/google/gopacket v1.1.19 @@ -19,44 +19,45 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/jbenet/go-temp-err-catcher v0.1.0 - github.com/klauspost/compress v1.16.4 + github.com/klauspost/compress v1.16.7 github.com/libp2p/go-buffer-pool v0.1.0 github.com/libp2p/go-flow-metrics v0.1.0 github.com/libp2p/go-libp2p-asn-util v0.3.0 github.com/libp2p/go-libp2p-testing v0.12.0 github.com/libp2p/go-mplex v0.7.0 github.com/libp2p/go-msgio v0.3.0 - github.com/libp2p/go-nat v0.1.0 + github.com/libp2p/go-nat v0.2.0 github.com/libp2p/go-netroute v0.2.1 - github.com/libp2p/go-reuseport v0.2.0 - github.com/libp2p/go-yamux/v4 v4.0.0 + github.com/libp2p/go-reuseport v0.3.0 + github.com/libp2p/go-yamux/v4 v4.0.1 github.com/libp2p/zeroconf/v2 v2.2.0 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b - github.com/minio/sha256-simd v1.0.0 + github.com/minio/sha256-simd v1.0.1 github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.9.0 + github.com/multiformats/go-multiaddr v0.10.1 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multiaddr-fmt v0.1.0 github.com/multiformats/go-multibase v0.2.0 - github.com/multiformats/go-multicodec v0.8.1 - github.com/multiformats/go-multihash v0.2.1 + github.com/multiformats/go-multicodec v0.9.0 + github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-multistream v0.4.1 github.com/multiformats/go-varint v0.0.7 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/prometheus/client_golang v1.14.0 - github.com/quic-go/quic-go v0.33.0 + github.com/prometheus/client_model v0.4.0 + github.com/quic-go/quic-go v0.36.3 github.com/quic-go/webtransport-go v0.5.3 github.com/raulk/go-watchdog v1.3.0 - github.com/stretchr/testify v1.8.2 - go.uber.org/fx v1.19.2 + github.com/stretchr/testify v1.8.4 + go.uber.org/fx v1.20.0 go.uber.org/goleak v1.1.12 - golang.org/x/crypto v0.7.0 - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.7.0 - golang.org/x/tools v0.7.0 + golang.org/x/crypto v0.11.0 + golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.10.0 + golang.org/x/tools v0.11.0 google.golang.org/protobuf v1.30.0 ) @@ -80,39 +81,38 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect + github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/huin/goupnp v1.1.0 // indirect + github.com/huin/goupnp v1.2.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/mattn/go-isatty v0.0.18 // 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.53 // indirect + github.com/miekg/dns v1.1.55 // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/ginkgo/v2 v2.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect + github.com/quic-go/qtls-go1-19 v0.3.3 // indirect + github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.16.1 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/text v0.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.1.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index 2b27173403..c86dd13224 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,38 @@ 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.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/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/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/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/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= 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= @@ -10,24 +41,39 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy 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/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 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/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 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 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 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/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.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/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= @@ -46,9 +92,9 @@ 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.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +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 v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= @@ -63,6 +109,10 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn 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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 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= @@ -75,7 +125,19 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV 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-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +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-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-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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= @@ -88,61 +150,90 @@ 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/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.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.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.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/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.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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +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-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= +github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= 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.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 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/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +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/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= +github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/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= @@ -167,20 +258,27 @@ 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/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/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.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +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/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 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= @@ -203,16 +301,14 @@ github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= 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.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +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.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +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/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= @@ -221,16 +317,16 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN 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-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/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/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.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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= @@ -239,12 +335,15 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn 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.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +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= @@ -254,24 +353,26 @@ 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.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= +github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= 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.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= -github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +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.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= +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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -282,43 +383,61 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +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.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/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/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.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +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.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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +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 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/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 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= -github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= +github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= +github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= +github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/quic-go v0.36.3 h1:f+yOqeGhMoRX7/M3wmEw/djhzKWr15FtQysox85/834= +github.com/quic-go/quic-go v0.36.3/go.mod h1:qxQumdeKw5GmWs1OsTZZnOxzSI+RJWuhf1O8FN35L2o= 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= @@ -350,6 +469,9 @@ 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/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= @@ -363,18 +485,15 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6 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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/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/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -383,18 +502,25 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX 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/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= 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.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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +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.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= @@ -409,59 +535,109 @@ go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= 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-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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +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-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.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-20181011144130-49bb7cea24b1/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-20200520004742-59133d7f0dd7/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-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-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/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.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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= @@ -469,51 +645,90 @@ 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/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-20210603081109-ebe580a85c40/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-20220114195835-da31bd327af9/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-20220704084225-05e143d24a9e/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 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.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/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.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/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= @@ -521,18 +736,51 @@ 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-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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= 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= @@ -540,29 +788,93 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T 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/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/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-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-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/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.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/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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.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= @@ -576,8 +888,10 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD 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.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/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= @@ -586,8 +900,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= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +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/options.go b/options.go index 1809ec44ba..beb4930f7c 100644 --- a/options.go +++ b/options.go @@ -23,6 +23,7 @@ import ( "github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/p2p/host/autorelay" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + "github.com/libp2p/go-libp2p/p2p/net/swarm" tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" "github.com/libp2p/go-libp2p/p2p/protocol/holepunch" @@ -574,3 +575,25 @@ func PrometheusRegisterer(reg prometheus.Registerer) Option { return nil } } + +// DialRanker configures libp2p to use d as the dial ranker. To enable smart +// dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to +// disable smart dialing. +// Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead +func DialRanker(d network.DialRanker) Option { + return func(cfg *Config) error { + if cfg.DialRanker != nil { + return errors.New("dial ranker already configured") + } + cfg.DialRanker = d + return nil + } +} + +// SwarmOpts configures libp2p to use swarm with opts +func SwarmOpts(opts ...swarm.Option) Option { + return func(cfg *Config) error { + cfg.SwarmOpts = opts + return nil + } +} diff --git a/p2p/discovery/backoff/backoff.go b/p2p/discovery/backoff/backoff.go index bde2a70f70..3fdfc08544 100644 --- a/p2p/discovery/backoff/backoff.go +++ b/p2p/discovery/backoff/backoff.go @@ -13,7 +13,7 @@ var log = logging.Logger("discovery-backoff") type BackoffFactory func() BackoffStrategy -// BackoffStrategy describes how backoff will be implemented. BackoffStratgies are stateful. +// BackoffStrategy describes how backoff will be implemented. BackoffStrategies are stateful. type BackoffStrategy interface { // Delay calculates how long the next backoff duration should be, given the prior calls to Delay Delay() time.Duration diff --git a/p2p/discovery/routing/routing.go b/p2p/discovery/routing/routing.go index c312c32bc7..6fee75096e 100644 --- a/p2p/discovery/routing/routing.go +++ b/p2p/discovery/routing/routing.go @@ -31,7 +31,7 @@ func (d *RoutingDiscovery) Advertise(ctx context.Context, ns string, opts ...dis ttl := options.Ttl if ttl == 0 || ttl > 3*time.Hour { - // the DHT provider record validity is 24hrs, but it is recommnded to republish at least every 6hrs + // the DHT provider record validity is 24hrs, but it is recommended to republish at least every 6hrs // we go one step further and republish every 3hrs ttl = 3 * time.Hour } diff --git a/p2p/host/autonat/options.go b/p2p/host/autonat/options.go index 8e653f8163..dec62c5f1d 100644 --- a/p2p/host/autonat/options.go +++ b/p2p/host/autonat/options.go @@ -91,9 +91,9 @@ func UsingAddresses(addrFunc AddrFunc) Option { } } -// WithSchedule configures how agressively probes will be made to verify the +// WithSchedule configures how aggressively probes will be made to verify the // address of the host. retryInterval indicates how often probes should be made -// when the host lacks confident about its address, while refresh interval +// when the host lacks confidence about its address, while refreshInterval // is the schedule of periodic probes when the host believes it knows its // steady-state reachability. func WithSchedule(retryInterval, refreshInterval time.Duration) Option { diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index 8ec6256569..79f02e2c51 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -1,13 +1,11 @@ package basichost import ( - "bytes" "context" "errors" "fmt" "io" "net" - "sort" "sync" "time" @@ -253,6 +251,12 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) { } if opts.EnableHolePunching { + if opts.EnableMetrics { + hpOpts := []holepunch.Option{ + holepunch.WithMetricsTracer(holepunch.NewMetricsTracer(holepunch.WithRegisterer(opts.PrometheusRegisterer)))} + opts.HolePunchingOptions = append(hpOpts, opts.HolePunchingOptions...) + + } h.hps, err = holepunch.NewService(h, h.ids, opts.HolePunchingOptions...) if err != nil { return nil, fmt.Errorf("failed to create hole punch service: %w", err) @@ -587,11 +591,10 @@ func (h *BasicHost) EventBus() event.Bus { // // host.Mux().SetHandler(proto, handler) // -// (Threadsafe) +// (Thread-safe) func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler network.StreamHandler) { h.Mux().AddHandler(pid, func(p protocol.ID, rwc io.ReadWriteCloser) error { is := rwc.(network.Stream) - is.SetProtocol(p) handler(is) return nil }) @@ -605,7 +608,6 @@ func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler network.StreamHand func (h *BasicHost) SetStreamHandlerMatch(pid protocol.ID, m func(protocol.ID) bool, handler network.StreamHandler) { h.Mux().AddHandlerWithFunc(pid, m, func(p protocol.ID, rwc io.ReadWriteCloser) error { is := rwc.(network.Stream) - is.SetProtocol(p) handler(is) return nil }) @@ -625,11 +627,8 @@ func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) { // NewStream opens a new stream to given peer p, and writes a p2p/protocol // header with given protocol.ID. If there is no connection to p, attempts // to create one. If ProtocolID is "", writes no header. -// (Threadsafe) +// (Thread-safe) func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error) { - // Ensure we have a connection, with peer addresses resolved by the routing system (#207) - // It is not sufficient to let the underlying host connect, it will most likely not have - // any addresses for the peer without any prior connections. // If the caller wants to prevent the host from dialing, it should use the NoDial option. if nodial, _ := network.GetNoDial(ctx); !nodial { err := h.Connect(ctx, peer.AddrInfo{ID: p}) @@ -645,7 +644,7 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I if errors.Is(err, network.ErrNoConn) { return nil, errors.New("connection failed") } - return nil, err + return nil, fmt.Errorf("failed to open stream: %w", err) } // Wait for any in-progress identifies on the connection to finish. This @@ -657,7 +656,7 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I case <-h.ids.IdentifyWait(s.Conn()): case <-ctx.Done(): _ = s.Reset() - return nil, ctx.Err() + return nil, fmt.Errorf("identify failed to complete: %w", ctx.Err()) } pref, err := h.preferredProtocol(p, pids) @@ -686,13 +685,13 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I case err = <-errCh: if err != nil { s.Reset() - return nil, err + return nil, fmt.Errorf("failed to negotiate protocol: %w", err) } case <-ctx.Done(): s.Reset() // wait for `SelectOneOf` to error out because of resetting the stream. <-errCh - return nil, ctx.Err() + return nil, fmt.Errorf("failed to negotiate protocol: %w", ctx.Err()) } s.SetProtocol(selected) @@ -738,7 +737,7 @@ func (h *BasicHost) dialPeer(ctx context.Context, p peer.ID) error { log.Debugf("host %s dialing %s", h.ID(), p) c, err := h.Network().DialPeer(ctx, p) if err != nil { - return err + return fmt.Errorf("failed to dial: %w", err) } // TODO: Consider removing this? On one hand, it's nice because we can @@ -749,7 +748,7 @@ func (h *BasicHost) dialPeer(ctx context.Context, p peer.ID) error { select { case <-h.ids.IdentifyWait(c): case <-ctx.Done(): - return ctx.Err() + return fmt.Errorf("identify failed to complete: %w", ctx.Err()) } log.Debugf("host %s finished dialing %s", h.ID(), p) @@ -815,26 +814,6 @@ func (h *BasicHost) NormalizeMultiaddr(addr ma.Multiaddr) ma.Multiaddr { return addr } -// dedupAddrs deduplicates addresses in place, leave only unique addresses. -// It doesn't allocate. -func dedupAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { - if len(addrs) == 0 { - return addrs - } - sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) < 0 }) - idx := 1 - for i := 1; i < len(addrs); i++ { - if !addrs[i-1].Equal(addrs[i]) { - addrs[idx] = addrs[i] - idx++ - } - } - for i := idx; i < len(addrs); i++ { - addrs[i] = nil - } - return addrs[:idx] -} - // AllAddrs returns all the addresses of BasicHost at this moment in time. // It's ok to not include addresses if they're not available to be used now. func (h *BasicHost) AllAddrs() []ma.Multiaddr { @@ -859,13 +838,12 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr { finalAddrs = append(finalAddrs, resolved...) } - finalAddrs = dedupAddrs(finalAddrs) + finalAddrs = ma.Unique(finalAddrs) - // natmgr is nil if we do not use nat option; - if h.natmgr != nil { + // use nat mappings if we have them + if h.natmgr != nil && h.natmgr.HasDiscoveredNAT() { // We have successfully mapped ports on our NAT. Use those // instead of observed addresses (mostly). - // Next, apply this mapping to our addresses. for _, listen := range listenAddrs { extMaddr := h.natmgr.GetMapping(listen) @@ -929,7 +907,7 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr { } finalAddrs = append(finalAddrs, observedAddrs...) } - finalAddrs = dedupAddrs(finalAddrs) + finalAddrs = ma.Unique(finalAddrs) finalAddrs = inferWebtransportAddrsFromQuic(finalAddrs) return finalAddrs diff --git a/p2p/host/basic/basic_host_test.go b/p2p/host/basic/basic_host_test.go index 19ea2bd02f..1093da3121 100644 --- a/p2p/host/basic/basic_host_test.go +++ b/p2p/host/basic/basic_host_test.go @@ -739,7 +739,7 @@ func TestNegotiationCancel(t *testing.T) { select { case err := <-errCh: - require.Equal(t, err, context.Canceled) + require.ErrorIs(t, err, context.Canceled) case <-time.After(500 * time.Millisecond): // failed to cancel t.Fatal("expected negotiation to be canceled") @@ -825,32 +825,6 @@ func TestNormalizeMultiaddr(t *testing.T) { require.Equal(t, "/ip4/1.2.3.4/udp/9999/quic-v1/webtransport", h1.NormalizeMultiaddr(ma.StringCast("/ip4/1.2.3.4/udp/9999/quic-v1/webtransport/certhash/uEgNmb28")).String()) } -func TestDedupAddrs(t *testing.T) { - tcpAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234") - quicAddr := ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1") - wsAddr := ma.StringCast("/ip4/127.0.0.1/tcp/1234/ws") - - type testcase struct { - in, out []ma.Multiaddr - } - - for i, tc := range []testcase{ - {in: nil, out: nil}, - {in: []ma.Multiaddr{tcpAddr}, out: []ma.Multiaddr{tcpAddr}}, - {in: []ma.Multiaddr{tcpAddr, tcpAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr}}, - {in: []ma.Multiaddr{tcpAddr, quicAddr, tcpAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr}}, - {in: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}, out: []ma.Multiaddr{tcpAddr, quicAddr, wsAddr}}, - } { - tc := tc - t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) { - deduped := dedupAddrs(tc.in) - for _, a := range tc.out { - require.Contains(t, deduped, a) - } - }) - } -} - func TestInferWebtransportAddrsFromQuic(t *testing.T) { type testCase struct { name string diff --git a/p2p/host/basic/mock_nat_test.go b/p2p/host/basic/mock_nat_test.go index 7714b25853..4e686fac12 100644 --- a/p2p/host/basic/mock_nat_test.go +++ b/p2p/host/basic/mock_nat_test.go @@ -5,6 +5,7 @@ package basichost import ( + context "context" netip "net/netip" reflect "reflect" @@ -35,17 +36,17 @@ func (m *MockNAT) EXPECT() *MockNATMockRecorder { } // AddMapping mocks base method. -func (m *MockNAT) AddMapping(arg0 string, arg1 int) error { +func (m *MockNAT) AddMapping(arg0 context.Context, arg1 string, arg2 int) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddMapping", arg0, arg1) + ret := m.ctrl.Call(m, "AddMapping", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // AddMapping indicates an expected call of AddMapping. -func (mr *MockNATMockRecorder) AddMapping(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) AddMapping(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMapping", reflect.TypeOf((*MockNAT)(nil).AddMapping), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMapping", reflect.TypeOf((*MockNAT)(nil).AddMapping), arg0, arg1, arg2) } // Close mocks base method. @@ -78,15 +79,15 @@ func (mr *MockNATMockRecorder) GetMapping(arg0, arg1 interface{}) *gomock.Call { } // RemoveMapping mocks base method. -func (m *MockNAT) RemoveMapping(arg0 string, arg1 int) error { +func (m *MockNAT) RemoveMapping(arg0 context.Context, arg1 string, arg2 int) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RemoveMapping", arg0, arg1) + ret := m.ctrl.Call(m, "RemoveMapping", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // RemoveMapping indicates an expected call of RemoveMapping. -func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMapping", reflect.TypeOf((*MockNAT)(nil).RemoveMapping), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMapping", reflect.TypeOf((*MockNAT)(nil).RemoveMapping), arg0, arg1, arg2) } diff --git a/p2p/host/basic/natmgr.go b/p2p/host/basic/natmgr.go index 6ebe37b9b7..8e8fbea347 100644 --- a/p2p/host/basic/natmgr.go +++ b/p2p/host/basic/natmgr.go @@ -21,6 +21,7 @@ import ( // and tries to obtain port mappings for those. type NATManager interface { GetMapping(ma.Multiaddr) ma.Multiaddr + HasDiscoveredNAT() bool io.Closer } @@ -35,8 +36,8 @@ type entry struct { } type nat interface { - AddMapping(protocol string, port int) error - RemoveMapping(protocol string, port int) error + AddMapping(ctx context.Context, protocol string, port int) error + RemoveMapping(ctx context.Context, protocol string, port int) error GetMapping(protocol string, port int) (netip.AddrPort, bool) io.Closer } @@ -60,6 +61,7 @@ type natManager struct { tracked map[entry]bool // the bool is only used in doSync and has no meaning outside of that function refCount sync.WaitGroup + ctx context.Context ctxCancel context.CancelFunc } @@ -68,6 +70,7 @@ func newNATManager(net network.Network) *natManager { nmgr := &natManager{ net: net, syncFlag: make(chan struct{}, 1), + ctx: ctx, ctxCancel: cancel, tracked: make(map[entry]bool), } @@ -84,6 +87,12 @@ func (nmgr *natManager) Close() error { return nil } +func (nmgr *natManager) HasDiscoveredNAT() bool { + nmgr.natMx.RLock() + defer nmgr.natMx.RUnlock() + return nmgr.nat != nil +} + func (nmgr *natManager) background(ctx context.Context) { defer nmgr.refCount.Done() @@ -192,14 +201,14 @@ func (nmgr *natManager) doSync() { // Close old mappings for e, v := range nmgr.tracked { if !v { - nmgr.nat.RemoveMapping(e.protocol, e.port) + nmgr.nat.RemoveMapping(nmgr.ctx, e.protocol, e.port) delete(nmgr.tracked, e) } } // Create new mappings. for _, e := range newAddresses { - if err := nmgr.nat.AddMapping(e.protocol, e.port); err != nil { + if err := nmgr.nat.AddMapping(nmgr.ctx, e.protocol, e.port); err != nil { log.Errorf("failed to port-map %s port %d: %s", e.protocol, e.port, err) } nmgr.tracked[e] = false diff --git a/p2p/host/basic/natmgr_test.go b/p2p/host/basic/natmgr_test.go index e507b45c82..d22092d188 100644 --- a/p2p/host/basic/natmgr_test.go +++ b/p2p/host/basic/natmgr_test.go @@ -76,7 +76,7 @@ func TestAddAndRemoveListeners(t *testing.T) { added := make(chan struct{}, 1) // add a TCP listener - mockNAT.EXPECT().AddMapping("tcp", 1234).Do(func(string, int) { added <- struct{}{} }) + mockNAT.EXPECT().AddMapping(gomock.Any(), "tcp", 1234).Do(func(context.Context, string, int) { added <- struct{}{} }) require.NoError(t, sw.Listen(ma.StringCast("/ip4/0.0.0.0/tcp/1234"))) select { case <-added: @@ -85,7 +85,7 @@ func TestAddAndRemoveListeners(t *testing.T) { } // add a QUIC listener - mockNAT.EXPECT().AddMapping("udp", 1234).Do(func(string, int) { added <- struct{}{} }) + mockNAT.EXPECT().AddMapping(gomock.Any(), "udp", 1234).Do(func(context.Context, string, int) { added <- struct{}{} }) require.NoError(t, sw.Listen(ma.StringCast("/ip4/0.0.0.0/udp/1234/quic-v1"))) select { case <-added: @@ -94,7 +94,7 @@ func TestAddAndRemoveListeners(t *testing.T) { } // remove the QUIC listener - mockNAT.EXPECT().RemoveMapping("udp", 1234).Do(func(string, int) { added <- struct{}{} }) + mockNAT.EXPECT().RemoveMapping(gomock.Any(), "udp", 1234).Do(func(context.Context, string, int) { added <- struct{}{} }) sw.ListenClose(ma.StringCast("/ip4/0.0.0.0/udp/1234/quic-v1")) select { case <-added: @@ -103,6 +103,6 @@ func TestAddAndRemoveListeners(t *testing.T) { } // test shutdown - mockNAT.EXPECT().RemoveMapping("tcp", 1234).MaxTimes(1) + mockNAT.EXPECT().RemoveMapping(gomock.Any(), "tcp", 1234).MaxTimes(1) mockNAT.EXPECT().Close().MaxTimes(1) } diff --git a/p2p/host/blank/blank.go b/p2p/host/blank/blank.go index 9f3daeff23..24304498b0 100644 --- a/p2p/host/blank/blank.go +++ b/p2p/host/blank/blank.go @@ -136,6 +136,9 @@ func (bh *BlankHost) Connect(ctx context.Context, ai peer.AddrInfo) error { } _, err := bh.Network().DialPeer(ctx, ai.ID) + if err != nil { + return fmt.Errorf("failed to dial: %w", err) + } return err } @@ -150,13 +153,13 @@ func (bh *BlankHost) ID() peer.ID { func (bh *BlankHost) NewStream(ctx context.Context, p peer.ID, protos ...protocol.ID) (network.Stream, error) { s, err := bh.n.NewStream(ctx, p) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to open stream: %w", err) } selected, err := mstream.SelectOneOf(protos, s) if err != nil { s.Reset() - return nil, err + return nil, fmt.Errorf("failed to negotiate protocol: %w", err) } s.SetProtocol(selected) diff --git a/p2p/host/peerstore/pstoremem/peerstore.go b/p2p/host/peerstore/pstoremem/peerstore.go index ec403f84c0..d5a41cc56a 100644 --- a/p2p/host/peerstore/pstoremem/peerstore.go +++ b/p2p/host/peerstore/pstoremem/peerstore.go @@ -22,7 +22,7 @@ var _ peerstore.Peerstore = &pstoremem{} type Option interface{} -// NewPeerstore creates an in-memory threadsafe collection of peers. +// NewPeerstore creates an in-memory thread-safe collection of peers. // It's the caller's responsibility to call RemovePeer to ensure // that memory consumption of the peerstore doesn't grow unboundedly. func NewPeerstore(opts ...Option) (ps *pstoremem, err error) { diff --git a/p2p/host/resource-manager/README.md b/p2p/host/resource-manager/README.md index 85926100f6..9371832c9a 100644 --- a/p2p/host/resource-manager/README.md +++ b/p2p/host/resource-manager/README.md @@ -47,15 +47,10 @@ limits := cfg.Build(scaledDefaultLimits) // The resource manager expects a limiter, se we create one from our limits. limiter := rcmgr.NewFixedLimiter(limits) -// (Optional if you want metrics) -rcmgrObs.MustRegisterWith(prometheus.DefaultRegisterer) -str, err := rcmgrObs.NewStatsTraceReporter() -if err != nil { - panic(err) -} - +// Metrics are enabled by default. If you want to disable metrics, use the +// WithMetricsDisabled option // Initialize the resource manager -rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str)) +rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithMetricsDisabled()) if err != nil { panic(err) } @@ -332,7 +327,7 @@ and streams. ### Scaling Limits When building software that is supposed to run on many different kind of machines, -with various memory and CPU configurations, it is desireable to have limits that +with various memory and CPU configurations, it is desirable to have limits that scale with the size of the machine. This is done using the `ScalingLimitConfig`. For every scope, this configuration @@ -495,7 +490,7 @@ or any other platform that can scrape a prometheus endpoint. There is also an included Grafana dashboard to help kickstart your observability into the resource manager. Find more information about it at -[here](./obs/grafana-dashboards/README.md). +[here](./../../../dashboards/resource-manager/README.md). ## Allowlisting multiaddrs to mitigate eclipse attacks diff --git a/p2p/host/resource-manager/limit_config_test.go b/p2p/host/resource-manager/limit_config_test.go index d1c5a81619..d7bd11061c 100644 --- a/p2p/host/resource-manager/limit_config_test.go +++ b/p2p/host/resource-manager/limit_config_test.go @@ -123,6 +123,25 @@ func TestLimitConfigRoundTrip(t *testing.T) { require.Equal(t, concreteCfg, concreteCfgRT) } +func TestDefaultsDontChange(t *testing.T) { + concrete := DefaultLimits.Scale(8<<30, 16<<10) // 8GB, 16k fds + jsonBytes, err := json.MarshalIndent(concrete.ToPartialLimitConfig(), "", " ") + require.NoError(t, err) + + // Uncomment to update the defaults file + // err = os.WriteFile("limit_config_test_default.json", jsonBytes, 0644) + // require.NoError(t, err) + + defaultsFromFile, err := os.ReadFile("limit_config_test_default.json") + require.NoError(t, err) + + // replace crlf with lf because of windows + defaultsFromFile = bytes.ReplaceAll(defaultsFromFile, []byte("\r\n"), []byte("\n")) + jsonBytes = bytes.ReplaceAll(jsonBytes, []byte("\r\n"), []byte("\n")) + + require.Equal(t, string(defaultsFromFile), string(jsonBytes)) +} + func TestReadmeLimitConfigSerialization(t *testing.T) { noisyNeighbor, _ := peer.Decode("QmVvtzcZgCkMnSFf2dnrBPXrWuNFWNM9J3MpZQCvWPuVZf") cfg := PartialLimitConfig{ diff --git a/p2p/host/resource-manager/limit_config_test_default.json b/p2p/host/resource-manager/limit_config_test_default.json new file mode 100644 index 0000000000..51fcba17c0 --- /dev/null +++ b/p2p/host/resource-manager/limit_config_test_default.json @@ -0,0 +1,112 @@ +{ + "System": { + "Streams": 18432, + "StreamsInbound": 9216, + "StreamsOutbound": 18432, + "Conns": 1152, + "ConnsInbound": 576, + "ConnsOutbound": 1152, + "FD": 16384, + "Memory": "8724152320" + }, + "Transient": { + "Streams": 2304, + "StreamsInbound": 1152, + "StreamsOutbound": 2304, + "Conns": 320, + "ConnsInbound": 160, + "ConnsOutbound": 320, + "FD": 4096, + "Memory": "1107296256" + }, + "AllowlistedSystem": { + "Streams": 18432, + "StreamsInbound": 9216, + "StreamsOutbound": 18432, + "Conns": 1152, + "ConnsInbound": 576, + "ConnsOutbound": 1152, + "FD": 16384, + "Memory": "8724152320" + }, + "AllowlistedTransient": { + "Streams": 2304, + "StreamsInbound": 1152, + "StreamsOutbound": 2304, + "Conns": 320, + "ConnsInbound": 160, + "ConnsOutbound": 320, + "FD": 4096, + "Memory": "1107296256" + }, + "ServiceDefault": { + "Streams": 20480, + "StreamsInbound": 5120, + "StreamsOutbound": 20480, + "Conns": "blockAll", + "ConnsInbound": "blockAll", + "ConnsOutbound": "blockAll", + "FD": "blockAll", + "Memory": "1140850688" + }, + "ServicePeerDefault": { + "Streams": 320, + "StreamsInbound": 160, + "StreamsOutbound": 320, + "Conns": "blockAll", + "ConnsInbound": "blockAll", + "ConnsOutbound": "blockAll", + "FD": "blockAll", + "Memory": "50331648" + }, + "ProtocolDefault": { + "Streams": 6144, + "StreamsInbound": 2560, + "StreamsOutbound": 6144, + "Conns": "blockAll", + "ConnsInbound": "blockAll", + "ConnsOutbound": "blockAll", + "FD": "blockAll", + "Memory": "1442840576" + }, + "ProtocolPeerDefault": { + "Streams": 384, + "StreamsInbound": 96, + "StreamsOutbound": 192, + "Conns": "blockAll", + "ConnsInbound": "blockAll", + "ConnsOutbound": "blockAll", + "FD": "blockAll", + "Memory": "16777248" + }, + "PeerDefault": { + "Streams": 2560, + "StreamsInbound": 1280, + "StreamsOutbound": 2560, + "Conns": 8, + "ConnsInbound": 8, + "ConnsOutbound": 8, + "FD": 256, + "Memory": "1140850688" + }, + "Conn": { + "Streams": "blockAll", + "StreamsInbound": "blockAll", + "StreamsOutbound": "blockAll", + "Conns": 1, + "ConnsInbound": 1, + "ConnsOutbound": 1, + "FD": 1, + "Memory": "33554432" + }, + "Stream": { + "Streams": 1, + "StreamsInbound": 1, + "StreamsOutbound": 1, + "Conns": "blockAll", + "ConnsInbound": "blockAll", + "ConnsOutbound": "blockAll", + "FD": "blockAll", + "Memory": "16777216" + } +} \ No newline at end of file diff --git a/p2p/host/resource-manager/obs/noalloc_test.go b/p2p/host/resource-manager/noalloc_test.go similarity index 73% rename from p2p/host/resource-manager/obs/noalloc_test.go rename to p2p/host/resource-manager/noalloc_test.go index 7b409865c6..461a001f9c 100644 --- a/p2p/host/resource-manager/obs/noalloc_test.go +++ b/p2p/host/resource-manager/noalloc_test.go @@ -1,6 +1,6 @@ //go:build nocover -package obs +package rcmgr import ( "math/rand" @@ -8,26 +8,25 @@ import ( "testing" "time" - rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" ) -func randomTraceEvt(rng *rand.Rand) rcmgr.TraceEvt { +func randomTraceEvt(rng *rand.Rand) TraceEvt { // Possibly non-sensical - typs := []rcmgr.TraceEvtTyp{ - rcmgr.TraceStartEvt, - rcmgr.TraceCreateScopeEvt, - rcmgr.TraceDestroyScopeEvt, - rcmgr.TraceReserveMemoryEvt, - rcmgr.TraceBlockReserveMemoryEvt, - rcmgr.TraceReleaseMemoryEvt, - rcmgr.TraceAddStreamEvt, - rcmgr.TraceBlockAddStreamEvt, - rcmgr.TraceRemoveStreamEvt, - rcmgr.TraceAddConnEvt, - rcmgr.TraceBlockAddConnEvt, - rcmgr.TraceRemoveConnEvt, + typs := []TraceEvtTyp{ + TraceStartEvt, + TraceCreateScopeEvt, + TraceDestroyScopeEvt, + TraceReserveMemoryEvt, + TraceBlockReserveMemoryEvt, + TraceReleaseMemoryEvt, + TraceAddStreamEvt, + TraceBlockAddStreamEvt, + TraceRemoveStreamEvt, + TraceAddConnEvt, + TraceBlockAddConnEvt, + TraceRemoveConnEvt, } names := []string{ @@ -43,7 +42,7 @@ func randomTraceEvt(rng *rand.Rand) rcmgr.TraceEvt { "service:libp2p.autonat.peer:12D3Koo", } - return rcmgr.TraceEvt{ + return TraceEvt{ Type: typs[rng.Intn(len(typs))], Name: names[rng.Intn(len(names))], DeltaOut: rng.Intn(5), @@ -60,7 +59,7 @@ func randomTraceEvt(rng *rand.Rand) rcmgr.TraceEvt { } -var registerOnce sync.Once +var regOnce sync.Once func BenchmarkMetricsRecording(b *testing.B) { b.ReportAllocs() @@ -70,7 +69,7 @@ func BenchmarkMetricsRecording(b *testing.B) { }) evtCount := 10000 - evts := make([]rcmgr.TraceEvt, evtCount) + evts := make([]TraceEvt, evtCount) rng := rand.New(rand.NewSource(int64(b.N))) for i := 0; i < evtCount; i++ { evts[i] = randomTraceEvt(rng) @@ -92,7 +91,7 @@ func TestNoAllocsNoCover(t *testing.T) { require.NoError(t, err) evtCount := 10_000 - evts := make([]rcmgr.TraceEvt, 0, evtCount) + evts := make([]TraceEvt, 0, evtCount) rng := rand.New(rand.NewSource(1)) for i := 0; i < evtCount; i++ { diff --git a/p2p/host/resource-manager/obs/obs.go b/p2p/host/resource-manager/obs/obs.go new file mode 100644 index 0000000000..3484fae4b2 --- /dev/null +++ b/p2p/host/resource-manager/obs/obs.go @@ -0,0 +1,18 @@ +// Package obs implements metrics tracing for resource manager +// +// Deprecated: obs is deprecated and the exported types and methods +// are moved to rcmgr package. Use the corresponding identifier in +// the rcmgr package, for example +// obs.NewStatsTraceReporter => rcmgr.NewStatsTraceReporter +package obs + +import ( + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" +) + +var MustRegisterWith = rcmgr.MustRegisterWith + +// StatsTraceReporter reports stats on the resource manager using its traces. +type StatsTraceReporter = rcmgr.StatsTraceReporter + +var NewStatsTraceReporter = rcmgr.NewStatsTraceReporter diff --git a/p2p/host/resource-manager/rcmgr.go b/p2p/host/resource-manager/rcmgr.go index 7f15bb7685..188a171f56 100644 --- a/p2p/host/resource-manager/rcmgr.go +++ b/p2p/host/resource-manager/rcmgr.go @@ -20,8 +20,9 @@ var log = logging.Logger("rcmgr") type resourceManager struct { limits Limiter - trace *trace - metrics *metrics + trace *trace + metrics *metrics + disableMetrics bool allowlist *Allowlist @@ -141,6 +142,28 @@ func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager } } + if !r.disableMetrics { + var sr TraceReporter + sr, err := NewStatsTraceReporter() + if err != nil { + log.Errorf("failed to initialise StatsTraceReporter %s", err) + } else { + if r.trace == nil { + r.trace = &trace{} + } + found := false + for _, rep := range r.trace.reporters { + if rep == sr { + found = true + break + } + } + if !found { + r.trace.reporters = append(r.trace.reporters, sr) + } + } + } + if err := r.trace.Start(limits); err != nil { return nil, err } diff --git a/p2p/host/resource-manager/obs/stats.go b/p2p/host/resource-manager/stats.go similarity index 87% rename from p2p/host/resource-manager/obs/stats.go rename to p2p/host/resource-manager/stats.go index bae3f09981..fd0772948a 100644 --- a/p2p/host/resource-manager/obs/stats.go +++ b/p2p/host/resource-manager/stats.go @@ -1,9 +1,8 @@ -package obs +package rcmgr import ( "strings" - rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/libp2p/go-libp2p/p2p/metricshelper" "github.com/prometheus/client_golang/prometheus" ) @@ -74,7 +73,7 @@ var ( previousPeerStreamsOutbound = previousPeerStreams.With(prometheus.Labels{"dir": "outbound"}) // Memory - memory = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + memoryTotal = prometheus.NewGaugeVec(prometheus.GaugeOpts{ Namespace: metricNamespace, Name: "memory", Help: "Amount of memory reserved as reported to the Resource Manager", @@ -142,7 +141,7 @@ var ( ) func MustRegisterWith(reg prometheus.Registerer) { - reg.MustRegister( + metricshelper.RegisterCollectors(reg, conns, peerConns, previousPeerConns, @@ -151,7 +150,7 @@ func MustRegisterWith(reg prometheus.Registerer) { previousPeerStreams, - memory, + memoryTotal, peerMemory, previousPeerMemory, connMemory, @@ -161,6 +160,13 @@ func MustRegisterWith(reg prometheus.Registerer) { ) } +func WithMetricsDisabled() Option { + return func(r *resourceManager) error { + r.disableMetrics = true + return nil + } +} + // StatsTraceReporter reports stats on the resource manager using its traces. type StatsTraceReporter struct{} @@ -169,7 +175,7 @@ func NewStatsTraceReporter() (StatsTraceReporter, error) { return StatsTraceReporter{}, nil } -func (r StatsTraceReporter) ConsumeEvent(evt rcmgr.TraceEvt) { +func (r StatsTraceReporter) ConsumeEvent(evt TraceEvt) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) @@ -177,10 +183,10 @@ func (r StatsTraceReporter) ConsumeEvent(evt rcmgr.TraceEvt) { } // Separate func so that we can test that this function does not allocate. The syncPool may allocate. -func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags *[]string) { +func (r StatsTraceReporter) consumeEventWithLabelSlice(evt TraceEvt, tags *[]string) { switch evt.Type { - case rcmgr.TraceAddStreamEvt, rcmgr.TraceRemoveStreamEvt: - if p := rcmgr.PeerStrInScopeName(evt.Name); p != "" { + case TraceAddStreamEvt, TraceRemoveStreamEvt: + if p := PeerStrInScopeName(evt.Name); p != "" { // Aggregated peer stats. Counts how many peers have N number of streams open. // Uses two buckets aggregations. One to count how many streams the // peer has now. The other to count the negative value, or how many @@ -210,11 +216,11 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } } else { if evt.DeltaOut != 0 { - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { + if IsSystemScope(evt.Name) || IsTransientScope(evt.Name) { *tags = (*tags)[:0] *tags = append(*tags, "outbound", evt.Name, "") streams.WithLabelValues(*tags...).Set(float64(evt.StreamsOut)) - } else if proto := rcmgr.ParseProtocolScopeName(evt.Name); proto != "" { + } else if proto := ParseProtocolScopeName(evt.Name); proto != "" { *tags = (*tags)[:0] *tags = append(*tags, "outbound", "protocol", proto) streams.WithLabelValues(*tags...).Set(float64(evt.StreamsOut)) @@ -227,11 +233,11 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } if evt.DeltaIn != 0 { - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { + if IsSystemScope(evt.Name) || IsTransientScope(evt.Name) { *tags = (*tags)[:0] *tags = append(*tags, "inbound", evt.Name, "") streams.WithLabelValues(*tags...).Set(float64(evt.StreamsIn)) - } else if proto := rcmgr.ParseProtocolScopeName(evt.Name); proto != "" { + } else if proto := ParseProtocolScopeName(evt.Name); proto != "" { *tags = (*tags)[:0] *tags = append(*tags, "inbound", "protocol", proto) streams.WithLabelValues(*tags...).Set(float64(evt.StreamsIn)) @@ -244,8 +250,8 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } } - case rcmgr.TraceAddConnEvt, rcmgr.TraceRemoveConnEvt: - if p := rcmgr.PeerStrInScopeName(evt.Name); p != "" { + case TraceAddConnEvt, TraceRemoveConnEvt: + if p := PeerStrInScopeName(evt.Name); p != "" { // Aggregated peer stats. Counts how many peers have N number of connections. // Uses two buckets aggregations. One to count how many streams the // peer has now. The other to count the negative value, or how many @@ -274,31 +280,31 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } } } else { - if rcmgr.IsConnScope(evt.Name) { + if IsConnScope(evt.Name) { // Not measuring this. I don't think it's useful. break } - if rcmgr.IsSystemScope(evt.Name) { + if IsSystemScope(evt.Name) { connsInboundSystem.Set(float64(evt.ConnsIn)) connsOutboundSystem.Set(float64(evt.ConnsOut)) - } else if rcmgr.IsTransientScope(evt.Name) { + } else if IsTransientScope(evt.Name) { connsInboundTransient.Set(float64(evt.ConnsIn)) connsOutboundTransient.Set(float64(evt.ConnsOut)) } // Represents the delta in fds if evt.Delta != 0 { - if rcmgr.IsSystemScope(evt.Name) { + if IsSystemScope(evt.Name) { fdsSystem.Set(float64(evt.FD)) - } else if rcmgr.IsTransientScope(evt.Name) { + } else if IsTransientScope(evt.Name) { fdsTransient.Set(float64(evt.FD)) } } } - case rcmgr.TraceReserveMemoryEvt, rcmgr.TraceReleaseMemoryEvt: - if p := rcmgr.PeerStrInScopeName(evt.Name); p != "" { + case TraceReserveMemoryEvt, TraceReleaseMemoryEvt: + if p := PeerStrInScopeName(evt.Name); p != "" { oldMem := evt.Memory - evt.Delta if oldMem != evt.Memory { if oldMem != 0 { @@ -308,7 +314,7 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags peerMemory.Observe(float64(evt.Memory)) } } - } else if rcmgr.IsConnScope(evt.Name) { + } else if IsConnScope(evt.Name) { oldMem := evt.Memory - evt.Delta if oldMem != evt.Memory { if oldMem != 0 { @@ -319,14 +325,14 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } } } else { - if rcmgr.IsSystemScope(evt.Name) || rcmgr.IsTransientScope(evt.Name) { + if IsSystemScope(evt.Name) || IsTransientScope(evt.Name) { *tags = (*tags)[:0] *tags = append(*tags, evt.Name, "") - memory.WithLabelValues(*tags...).Set(float64(evt.Memory)) - } else if proto := rcmgr.ParseProtocolScopeName(evt.Name); proto != "" { + memoryTotal.WithLabelValues(*tags...).Set(float64(evt.Memory)) + } else if proto := ParseProtocolScopeName(evt.Name); proto != "" { *tags = (*tags)[:0] *tags = append(*tags, "protocol", proto) - memory.WithLabelValues(*tags...).Set(float64(evt.Memory)) + memoryTotal.WithLabelValues(*tags...).Set(float64(evt.Memory)) } else { // Not measuring connscope, servicepeer and protocolpeer. Lots of data, and // you can use aggregated peer stats + service stats to infer @@ -335,11 +341,11 @@ func (r StatsTraceReporter) consumeEventWithLabelSlice(evt rcmgr.TraceEvt, tags } } - case rcmgr.TraceBlockAddConnEvt, rcmgr.TraceBlockAddStreamEvt, rcmgr.TraceBlockReserveMemoryEvt: + case TraceBlockAddConnEvt, TraceBlockAddStreamEvt, TraceBlockReserveMemoryEvt: var resource string - if evt.Type == rcmgr.TraceBlockAddConnEvt { + if evt.Type == TraceBlockAddConnEvt { resource = "connection" - } else if evt.Type == rcmgr.TraceBlockAddStreamEvt { + } else if evt.Type == TraceBlockAddStreamEvt { resource = "stream" } else { resource = "memory" diff --git a/p2p/host/resource-manager/obs/stats_test.go b/p2p/host/resource-manager/stats_test.go similarity index 50% rename from p2p/host/resource-manager/obs/stats_test.go rename to p2p/host/resource-manager/stats_test.go index bc98a0eec3..b4f1ec996a 100644 --- a/p2p/host/resource-manager/obs/stats_test.go +++ b/p2p/host/resource-manager/stats_test.go @@ -1,19 +1,17 @@ -package obs_test +package rcmgr import ( "sync" "testing" "time" - rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" - "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" "github.com/prometheus/client_golang/prometheus" ) var registerOnce sync.Once func TestTraceReporterStartAndClose(t *testing.T) { - rcmgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(obs.StatsTraceReporter{})) + rcmgr, err := NewResourceManager(NewFixedLimiter(DefaultLimits.AutoScale()), WithTraceReporter(StatsTraceReporter{})) if err != nil { t.Fatal(err) } @@ -21,18 +19,18 @@ func TestTraceReporterStartAndClose(t *testing.T) { } func TestConsumeEvent(t *testing.T) { - evt := rcmgr.TraceEvt{ - Type: rcmgr.TraceBlockAddStreamEvt, + evt := TraceEvt{ + Type: TraceBlockAddStreamEvt, Name: "conn-1", DeltaOut: 1, Time: time.Now().Format(time.RFC3339Nano), } registerOnce.Do(func() { - obs.MustRegisterWith(prometheus.DefaultRegisterer) + MustRegisterWith(prometheus.DefaultRegisterer) }) - str, err := obs.NewStatsTraceReporter() + str, err := NewStatsTraceReporter() if err != nil { t.Fatal(err) } diff --git a/p2p/metricshelper/conn.go b/p2p/metricshelper/conn.go new file mode 100644 index 0000000000..ef367ac9b1 --- /dev/null +++ b/p2p/metricshelper/conn.go @@ -0,0 +1,29 @@ +package metricshelper + +import ma "github.com/multiformats/go-multiaddr" + +var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP} + +func GetTransport(a ma.Multiaddr) string { + for _, t := range transports { + if _, err := a.ValueForProtocol(t); err == nil { + return ma.ProtocolWithCode(t).Name + } + } + return "other" +} + +func GetIPVersion(addr ma.Multiaddr) string { + version := "unknown" + ma.ForEach(addr, func(c ma.Component) bool { + if c.Protocol().Code == ma.P_IP4 { + version = "ip4" + return false + } else if c.Protocol().Code == ma.P_IP6 { + version = "ip6" + return false + } + return true + }) + return version +} diff --git a/p2p/net/mock/interface.go b/p2p/net/mock/interface.go index d89342b009..acb2563500 100644 --- a/p2p/net/mock/interface.go +++ b/p2p/net/mock/interface.go @@ -10,6 +10,7 @@ import ( "io" "time" + "github.com/libp2p/go-libp2p/core/connmgr" ic "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" @@ -19,14 +20,24 @@ import ( ma "github.com/multiformats/go-multiaddr" ) +type PeerOptions struct { + // ps is the Peerstore to use when adding peer. If nil, a default peerstore will be created. + ps peerstore.Peerstore + + // gater is the ConnectionGater to use when adding a peer. If nil, no connection gater will be used. + gater connmgr.ConnectionGater +} + type Mocknet interface { // GenPeer generates a peer and its network.Network in the Mocknet GenPeer() (host.Host, error) + GenPeerWithOptions(PeerOptions) (host.Host, error) // AddPeer adds an existing peer. we need both a privkey and addr. // ID is derived from PrivKey AddPeer(ic.PrivKey, ma.Multiaddr) (host.Host, error) AddPeerWithPeerstore(peer.ID, peerstore.Peerstore) (host.Host, error) + AddPeerWithOptions(peer.ID, PeerOptions) (host.Host, error) // retrieve things (with randomized iteration order) Peers() []peer.ID diff --git a/p2p/net/mock/mock_net.go b/p2p/net/mock/mock_net.go index cde4052369..43294d4a54 100644 --- a/p2p/net/mock/mock_net.go +++ b/p2p/net/mock/mock_net.go @@ -64,6 +64,13 @@ func (mn *mocknet) Close() error { } func (mn *mocknet) GenPeer() (host.Host, error) { + return mn.GenPeerWithOptions(PeerOptions{}) +} + +func (mn *mocknet) GenPeerWithOptions(opts PeerOptions) (host.Host, error) { + if err := mn.addDefaults(&opts); err != nil { + return nil, err + } sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader) if err != nil { return nil, err @@ -83,7 +90,20 @@ func (mn *mocknet) GenPeer() (host.Host, error) { return nil, fmt.Errorf("failed to create test multiaddr: %s", err) } - h, err := mn.AddPeer(sk, a) + var ps peerstore.Peerstore + if opts.ps == nil { + ps, err = pstoremem.NewPeerstore() + if err != nil { + return nil, err + } + } else { + ps = opts.ps + } + p, err := mn.updatePeerstore(sk, a, ps) + if err != nil { + return nil, err + } + h, err := mn.AddPeerWithOptions(p, opts) if err != nil { return nil, err } @@ -92,36 +112,39 @@ func (mn *mocknet) GenPeer() (host.Host, error) { } func (mn *mocknet) AddPeer(k ic.PrivKey, a ma.Multiaddr) (host.Host, error) { - p, err := peer.IDFromPublicKey(k.GetPublic()) + ps, err := pstoremem.NewPeerstore() if err != nil { return nil, err } - - ps, err := pstoremem.NewPeerstore() + p, err := mn.updatePeerstore(k, a, ps) if err != nil { return nil, err } - ps.AddAddr(p, a, peerstore.PermanentAddrTTL) - ps.AddPrivKey(p, k) - ps.AddPubKey(p, k.GetPublic()) return mn.AddPeerWithPeerstore(p, ps) } func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peerstore.Peerstore) (host.Host, error) { + return mn.AddPeerWithOptions(p, PeerOptions{ps: ps}) +} + +func (mn *mocknet) AddPeerWithOptions(p peer.ID, opts PeerOptions) (host.Host, error) { bus := eventbus.NewBus() - n, err := newPeernet(mn, p, ps, bus) + if err := mn.addDefaults(&opts); err != nil { + return nil, err + } + n, err := newPeernet(mn, p, opts, bus) if err != nil { return nil, err } - opts := &bhost.HostOpts{ + hostOpts := &bhost.HostOpts{ NegotiationTimeout: -1, DisableSignedPeerRecord: true, EventBus: bus, } - h, err := bhost.NewHost(n, opts) + h, err := bhost.NewHost(n, hostOpts) if err != nil { return nil, err } @@ -134,6 +157,35 @@ func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peerstore.Peerstore) (host return h, nil } +func (mn *mocknet) addDefaults(opts *PeerOptions) error { + if opts.ps == nil { + ps, err := pstoremem.NewPeerstore() + if err != nil { + return err + } + opts.ps = ps + } + return nil +} + +func (mn *mocknet) updatePeerstore(k ic.PrivKey, a ma.Multiaddr, ps peerstore.Peerstore) (peer.ID, error) { + p, err := peer.IDFromPublicKey(k.GetPublic()) + if err != nil { + return "", err + } + + ps.AddAddr(p, a, peerstore.PermanentAddrTTL) + err = ps.AddPrivKey(p, k) + if err != nil { + return "", err + } + err = ps.AddPubKey(p, k.GetPublic()) + if err != nil { + return "", err + } + return p, nil +} + func (mn *mocknet) Peers() []peer.ID { mn.Lock() defer mn.Unlock() diff --git a/p2p/net/mock/mock_peernet.go b/p2p/net/mock/mock_peernet.go index a46ee8ddc9..2e56b7f2bb 100644 --- a/p2p/net/mock/mock_peernet.go +++ b/p2p/net/mock/mock_peernet.go @@ -7,6 +7,7 @@ import ( "math/rand" "sync" + "github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" @@ -28,6 +29,9 @@ type peernet struct { connsByPeer map[peer.ID]map[*conn]struct{} connsByLink map[*link]map[*conn]struct{} + // connection gater to check before dialing or accepting connections. May be nil to allow all. + gater connmgr.ConnectionGater + // implement network.Network streamHandler network.StreamHandler @@ -38,7 +42,7 @@ type peernet struct { } // newPeernet constructs a new peernet -func newPeernet(m *mocknet, p peer.ID, ps peerstore.Peerstore, bus event.Bus) (*peernet, error) { +func newPeernet(m *mocknet, p peer.ID, opts PeerOptions, bus event.Bus) (*peernet, error) { emitter, err := bus.Emitter(&event.EvtPeerConnectednessChanged{}) if err != nil { return nil, err @@ -47,7 +51,8 @@ func newPeernet(m *mocknet, p peer.ID, ps peerstore.Peerstore, bus event.Bus) (* n := &peernet{ mocknet: m, peer: p, - ps: ps, + ps: opts.ps, + gater: opts.gater, emitter: emitter, connsByPeer: map[peer.ID]map[*conn]struct{}{}, @@ -124,6 +129,10 @@ func (pn *peernet) connect(p peer.ID) (*conn, error) { } pn.RUnlock() + if pn.gater != nil && !pn.gater.InterceptPeerDial(p) { + log.Debugf("gater disallowed outbound connection to peer %s", p) + return nil, fmt.Errorf("%v connection gater disallowed connection to %v", pn.peer, p) + } log.Debugf("%s (newly) dialing %s", pn.peer, p) // ok, must create a new connection. we need a link @@ -139,18 +148,51 @@ func (pn *peernet) connect(p peer.ID) (*conn, error) { log.Debugf("%s dialing %s openingConn", pn.peer, p) // create a new connection with link - c := pn.openConn(p, l.(*link)) - return c, nil + return pn.openConn(p, l.(*link)) } -func (pn *peernet) openConn(r peer.ID, l *link) *conn { +func (pn *peernet) openConn(r peer.ID, l *link) (*conn, error) { lc, rc := l.newConnPair(pn) - log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer()) addConnPair(pn, rc.net, lc, rc) + log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer()) + abort := func() { + _ = lc.Close() + _ = rc.Close() + } + if pn.gater != nil && !pn.gater.InterceptAddrDial(lc.remote, lc.remoteAddr) { + abort() + return nil, fmt.Errorf("%v rejected dial to %v on addr %v", lc.local, lc.remote, lc.remoteAddr) + } + if rc.net.gater != nil && !rc.net.gater.InterceptAccept(rc) { + abort() + return nil, fmt.Errorf("%v rejected connection from %v", rc.local, rc.remote) + } + if err := checkSecureAndUpgrade(network.DirOutbound, pn.gater, lc); err != nil { + abort() + return nil, err + } + if err := checkSecureAndUpgrade(network.DirInbound, rc.net.gater, rc); err != nil { + abort() + return nil, err + } go rc.net.remoteOpenedConn(rc) pn.addConn(lc) - return lc + return lc, nil +} + +func checkSecureAndUpgrade(dir network.Direction, gater connmgr.ConnectionGater, c *conn) error { + if gater == nil { + return nil + } + if !gater.InterceptSecured(dir, c.remote, c) { + return fmt.Errorf("%v rejected secure handshake with %v", c.local, c.remote) + } + allow, _ := gater.InterceptUpgraded(c) + if !allow { + return fmt.Errorf("%v rejected upgrade with %v", c.local, c.remote) + } + return nil } // addConnPair adds connection to both peernets at the same time @@ -358,7 +400,7 @@ func (pn *peernet) NewStream(ctx context.Context, p peer.ID) (network.Stream, er } // SetStreamHandler sets the new stream handler on the Network. -// This operation is threadsafe. +// This operation is thread-safe. func (pn *peernet) SetStreamHandler(h network.StreamHandler) { pn.Lock() pn.streamHandler = h diff --git a/p2p/net/mock/mock_test.go b/p2p/net/mock/mock_test.go index 2ea1bf18dd..863e54f1c7 100644 --- a/p2p/net/mock/mock_test.go +++ b/p2p/net/mock/mock_test.go @@ -13,9 +13,12 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/event" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" + "github.com/libp2p/go-libp2p/p2p/net/conngater" + manet "github.com/multiformats/go-multiaddr/net" "github.com/libp2p/go-libp2p-testing/ci" tetc "github.com/libp2p/go-libp2p-testing/etc" @@ -681,3 +684,68 @@ func TestEventBus(t *testing.T) { } } } + +func TestBlockByPeerID(t *testing.T) { + m, gater1, host1, _, host2 := WithConnectionGaters(t) + + err := gater1.BlockPeer(host2.ID()) + if err != nil { + t.Fatal(err) + } + + _, err = m.ConnectPeers(host1.ID(), host2.ID()) + if err == nil { + t.Fatal("Should have blocked connection to banned peer") + } + + _, err = m.ConnectPeers(host2.ID(), host1.ID()) + if err == nil { + t.Fatal("Should have blocked connection from banned peer") + } +} + +func TestBlockByIP(t *testing.T) { + m, gater1, host1, _, host2 := WithConnectionGaters(t) + + ip, err := manet.ToIP(host2.Addrs()[0]) + if err != nil { + t.Fatal(err) + } + err = gater1.BlockAddr(ip) + if err != nil { + t.Fatal(err) + } + + _, err = m.ConnectPeers(host1.ID(), host2.ID()) + if err == nil { + t.Fatal("Should have blocked connection to banned IP") + } + + _, err = m.ConnectPeers(host2.ID(), host1.ID()) + if err == nil { + t.Fatal("Should have blocked connection from banned IP") + } +} + +func WithConnectionGaters(t *testing.T) (Mocknet, *conngater.BasicConnectionGater, host.Host, *conngater.BasicConnectionGater, host.Host) { + m := New() + addPeer := func() (*conngater.BasicConnectionGater, host.Host) { + gater, err := conngater.NewBasicConnectionGater(nil) + if err != nil { + t.Fatal(err) + } + h, err := m.GenPeerWithOptions(PeerOptions{gater: gater}) + if err != nil { + t.Fatal(err) + } + return gater, h + } + gater1, host1 := addPeer() + gater2, host2 := addPeer() + + err := m.LinkAll() + if err != nil { + t.Fatal(err) + } + return m, gater1, host1, gater2, host2 +} diff --git a/p2p/net/nat/mock_nat_test.go b/p2p/net/nat/mock_nat_test.go index bb91bac247..c7a151fd10 100644 --- a/p2p/net/nat/mock_nat_test.go +++ b/p2p/net/nat/mock_nat_test.go @@ -5,6 +5,7 @@ package nat import ( + context "context" net "net" reflect "reflect" time "time" @@ -36,32 +37,32 @@ func (m *MockNAT) EXPECT() *MockNATMockRecorder { } // AddPortMapping mocks base method. -func (m *MockNAT) AddPortMapping(arg0 string, arg1 int, arg2 string, arg3 time.Duration) (int, error) { +func (m *MockNAT) AddPortMapping(arg0 context.Context, arg1 string, arg2 int, arg3 string, arg4 time.Duration) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddPortMapping", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "AddPortMapping", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } // AddPortMapping indicates an expected call of AddPortMapping. -func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPortMapping", reflect.TypeOf((*MockNAT)(nil).AddPortMapping), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPortMapping", reflect.TypeOf((*MockNAT)(nil).AddPortMapping), arg0, arg1, arg2, arg3, arg4) } // DeletePortMapping mocks base method. -func (m *MockNAT) DeletePortMapping(arg0 string, arg1 int) error { +func (m *MockNAT) DeletePortMapping(arg0 context.Context, arg1 string, arg2 int) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeletePortMapping", arg0, arg1) + ret := m.ctrl.Call(m, "DeletePortMapping", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // DeletePortMapping indicates an expected call of DeletePortMapping. -func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePortMapping", reflect.TypeOf((*MockNAT)(nil).DeletePortMapping), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePortMapping", reflect.TypeOf((*MockNAT)(nil).DeletePortMapping), arg0, arg1, arg2) } // GetDeviceAddress mocks base method. diff --git a/p2p/net/nat/nat.go b/p2p/net/nat/nat.go index 68834ac877..28ffd4a5b2 100644 --- a/p2p/net/nat/nat.go +++ b/p2p/net/nat/nat.go @@ -118,7 +118,7 @@ func (nat *NAT) GetMapping(protocol string, port int) (addr netip.AddrPort, foun // // May not succeed, and mappings may change over time; // NAT devices may not respect our port requests, and even lie. -func (nat *NAT) AddMapping(protocol string, port int) error { +func (nat *NAT) AddMapping(ctx context.Context, protocol string, port int) error { switch protocol { case "tcp", "udp": default: @@ -134,14 +134,14 @@ func (nat *NAT) AddMapping(protocol string, port int) error { // do it once synchronously, so first mapping is done right away, and before exiting, // allowing users -- in the optimistic case -- to use results right after. - extPort := nat.establishMapping(protocol, port) + extPort := nat.establishMapping(ctx, protocol, port) nat.mappings[entry{protocol: protocol, port: port}] = extPort return nil } // RemoveMapping removes a port mapping. // It blocks until the NAT has removed the mapping. -func (nat *NAT) RemoveMapping(protocol string, port int) error { +func (nat *NAT) RemoveMapping(ctx context.Context, protocol string, port int) error { nat.mappingmu.Lock() defer nat.mappingmu.Unlock() @@ -150,7 +150,7 @@ func (nat *NAT) RemoveMapping(protocol string, port int) error { e := entry{protocol: protocol, port: port} if _, ok := nat.mappings[e]; ok { delete(nat.mappings, e) - return nat.nat.DeletePortMapping(protocol, port) + return nat.nat.DeletePortMapping(ctx, protocol, port) } return errors.New("unknown mapping") default: @@ -184,7 +184,7 @@ func (nat *NAT) background() { // Establishing the mapping involves network requests. // Don't hold the mutex, just save the ports. for _, e := range in { - out = append(out, nat.establishMapping(e.protocol, e.port)) + out = append(out, nat.establishMapping(nat.ctx, e.protocol, e.port)) } nat.mappingmu.Lock() for i, p := range in { @@ -208,9 +208,11 @@ func (nat *NAT) background() { t.Reset(time.Until(minTime(nextAddrUpdate, nextMappingUpdate))) case <-nat.ctx.Done(): nat.mappingmu.Lock() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() for e := range nat.mappings { delete(nat.mappings, e) - nat.nat.DeletePortMapping(e.protocol, e.port) + nat.nat.DeletePortMapping(ctx, e.protocol, e.port) } nat.mappingmu.Unlock() return @@ -218,16 +220,16 @@ func (nat *NAT) background() { } } -func (nat *NAT) establishMapping(protocol string, internalPort int) (externalPort int) { +func (nat *NAT) establishMapping(ctx context.Context, protocol string, internalPort int) (externalPort int) { log.Debugf("Attempting port map: %s/%d", protocol, internalPort) const comment = "libp2p" nat.natmu.Lock() var err error - externalPort, err = nat.nat.AddPortMapping(protocol, internalPort, comment, MappingDuration) + externalPort, err = nat.nat.AddPortMapping(ctx, protocol, internalPort, comment, MappingDuration) if err != nil { // Some hardware does not support mappings with timeout, so try that - externalPort, err = nat.nat.AddPortMapping(protocol, internalPort, comment, 0) + externalPort, err = nat.nat.AddPortMapping(ctx, protocol, internalPort, comment, 0) } nat.natmu.Unlock() diff --git a/p2p/net/nat/nat_test.go b/p2p/net/nat/nat_test.go index 8fffb512c7..ea47edc0b3 100644 --- a/p2p/net/nat/nat_test.go +++ b/p2p/net/nat/nat_test.go @@ -36,8 +36,8 @@ func TestAddMapping(t *testing.T) { nat, err := DiscoverNAT(context.Background()) require.NoError(t, err) - mockNAT.EXPECT().AddPortMapping("tcp", 10000, gomock.Any(), MappingDuration).Return(1234, nil) - require.NoError(t, nat.AddMapping("tcp", 10000)) + mockNAT.EXPECT().AddPortMapping(gomock.Any(), "tcp", 10000, gomock.Any(), MappingDuration).Return(1234, nil) + require.NoError(t, nat.AddMapping(context.Background(), "tcp", 10000)) _, found := nat.GetMapping("tcp", 9999) require.False(t, found, "didn't expect a port mapping for unmapped port") @@ -55,14 +55,14 @@ func TestRemoveMapping(t *testing.T) { mockNAT.EXPECT().GetExternalAddress().Return(net.IPv4(1, 2, 3, 4), nil) nat, err := DiscoverNAT(context.Background()) require.NoError(t, err) - mockNAT.EXPECT().AddPortMapping("tcp", 10000, gomock.Any(), MappingDuration).Return(1234, nil) - require.NoError(t, nat.AddMapping("tcp", 10000)) + mockNAT.EXPECT().AddPortMapping(gomock.Any(), "tcp", 10000, gomock.Any(), MappingDuration).Return(1234, nil) + require.NoError(t, nat.AddMapping(context.Background(), "tcp", 10000)) _, found := nat.GetMapping("tcp", 10000) require.True(t, found, "expected port mapping") - require.Error(t, nat.RemoveMapping("tcp", 9999), "expected error for unknown mapping") - mockNAT.EXPECT().DeletePortMapping("tcp", 10000) - require.NoError(t, nat.RemoveMapping("tcp", 10000)) + require.Error(t, nat.RemoveMapping(context.Background(), "tcp", 9999), "expected error for unknown mapping") + mockNAT.EXPECT().DeletePortMapping(gomock.Any(), "tcp", 10000) + require.NoError(t, nat.RemoveMapping(context.Background(), "tcp", 10000)) _, found = nat.GetMapping("tcp", 10000) require.False(t, found, "didn't expect port mapping for deleted mapping") diff --git a/p2p/net/swarm/black_hole_detector.go b/p2p/net/swarm/black_hole_detector.go new file mode 100644 index 0000000000..078b1126c4 --- /dev/null +++ b/p2p/net/swarm/black_hole_detector.go @@ -0,0 +1,276 @@ +package swarm + +import ( + "fmt" + "sync" + + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +type blackHoleState int + +const ( + blackHoleStateProbing blackHoleState = iota + blackHoleStateAllowed + blackHoleStateBlocked +) + +func (st blackHoleState) String() string { + switch st { + case blackHoleStateProbing: + return "Probing" + case blackHoleStateAllowed: + return "Allowed" + case blackHoleStateBlocked: + return "Blocked" + default: + return fmt.Sprintf("Unknown %d", st) + } +} + +type blackHoleResult int + +const ( + blackHoleResultAllowed blackHoleResult = iota + blackHoleResultProbing + blackHoleResultBlocked +) + +// blackHoleFilter provides black hole filtering for dials. This filter should be used in +// concert with a UDP of IPv6 address filter to detect UDP or IPv6 black hole. In a black +// holed environments dial requests are blocked and only periodic probes to check the +// state of the black hole are allowed. +// +// Requests are blocked if the number of successes in the last n dials is less than +// minSuccesses. If a request succeeds in Blocked state, the filter state is reset and n +// subsequent requests are allowed before reevaluating black hole state. Dials cancelled +// when some other concurrent dial succeeded are counted as failures. A sufficiently large +// n prevents false negatives in such cases. +type blackHoleFilter struct { + // n serves the dual purpose of being the minimum number of requests after which we + // probe the state of the black hole in blocked state and the minimum number of + // completed dials required before evaluating black hole state. + n int + // minSuccesses is the minimum number of Success required in the last n dials + // to consider we are not blocked. + minSuccesses int + // name for the detector. + name string + + // requests counts number of dial requests to peers. We handle request at a peer + // level and record results at individual address dial level. + requests int + // dialResults of the last `n` dials. A successful dial is true. + dialResults []bool + // successes is the count of successful dials in outcomes + successes int + // state is the current state of the detector + state blackHoleState + + mu sync.Mutex + metricsTracer MetricsTracer +} + +// RecordResult records the outcome of a dial. A successful dial will change the state +// of the filter to Allowed. A failed dial only blocks subsequent requests if the success +// fraction over the last n outcomes is less than the minSuccessFraction of the filter. +func (b *blackHoleFilter) RecordResult(success bool) { + b.mu.Lock() + defer b.mu.Unlock() + + if b.state == blackHoleStateBlocked && success { + // If the call succeeds in a blocked state we reset to allowed. + // This is better than slowly accumulating values till we cross the minSuccessFraction + // threshold since a blackhole is a binary property. + b.reset() + return + } + + if success { + b.successes++ + } + b.dialResults = append(b.dialResults, success) + + if len(b.dialResults) > b.n { + if b.dialResults[0] { + b.successes-- + } + b.dialResults = b.dialResults[1:] + } + + b.updateState() + b.trackMetrics() +} + +// HandleRequest returns the result of applying the black hole filter for the request. +func (b *blackHoleFilter) HandleRequest() blackHoleResult { + b.mu.Lock() + defer b.mu.Unlock() + + b.requests++ + + b.trackMetrics() + + if b.state == blackHoleStateAllowed { + return blackHoleResultAllowed + } else if b.state == blackHoleStateProbing || b.requests%b.n == 0 { + return blackHoleResultProbing + } else { + return blackHoleResultBlocked + } +} + +func (b *blackHoleFilter) reset() { + b.successes = 0 + b.dialResults = b.dialResults[:0] + b.requests = 0 + b.updateState() +} + +func (b *blackHoleFilter) updateState() { + st := b.state + + if len(b.dialResults) < b.n { + b.state = blackHoleStateProbing + } else if b.successes >= b.minSuccesses { + b.state = blackHoleStateAllowed + } else { + b.state = blackHoleStateBlocked + } + + if st != b.state { + log.Debugf("%s blackHoleDetector state changed from %s to %s", b.name, st, b.state) + } +} + +func (b *blackHoleFilter) trackMetrics() { + if b.metricsTracer == nil { + return + } + + nextRequestAllowedAfter := 0 + if b.state == blackHoleStateBlocked { + nextRequestAllowedAfter = b.n - (b.requests % b.n) + } + + successFraction := 0.0 + if len(b.dialResults) > 0 { + successFraction = float64(b.successes) / float64(len(b.dialResults)) + } + + b.metricsTracer.UpdatedBlackHoleFilterState( + b.name, + b.state, + nextRequestAllowedAfter, + successFraction, + ) +} + +// blackHoleDetector provides UDP and IPv6 black hole detection using a `blackHoleFilter` +// for each. For details of the black hole detection logic see `blackHoleFilter`. +// +// black hole filtering is done at a peer dial level to ensure that periodic probes to +// detect change of the black hole state are actually dialed and are not skipped +// because of dial prioritisation logic. +type blackHoleDetector struct { + udp, ipv6 *blackHoleFilter +} + +// FilterAddrs filters the peer's addresses removing black holed addresses +func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { + hasUDP, hasIPv6 := false, false + for _, a := range addrs { + if !manet.IsPublicAddr(a) { + continue + } + if isProtocolAddr(a, ma.P_UDP) { + hasUDP = true + } + if isProtocolAddr(a, ma.P_IP6) { + hasIPv6 = true + } + } + + udpRes := blackHoleResultAllowed + if d.udp != nil && hasUDP { + udpRes = d.udp.HandleRequest() + } + + ipv6Res := blackHoleResultAllowed + if d.ipv6 != nil && hasIPv6 { + ipv6Res = d.ipv6.HandleRequest() + } + + return ma.FilterAddrs( + addrs, + func(a ma.Multiaddr) bool { + if !manet.IsPublicAddr(a) { + return true + } + // allow all UDP addresses while probing irrespective of IPv6 black hole state + if udpRes == blackHoleResultProbing && isProtocolAddr(a, ma.P_UDP) { + return true + } + // allow all IPv6 addresses while probing irrespective of UDP black hole state + if ipv6Res == blackHoleResultProbing && isProtocolAddr(a, ma.P_IP6) { + return true + } + + if udpRes == blackHoleResultBlocked && isProtocolAddr(a, ma.P_UDP) { + return false + } + if ipv6Res == blackHoleResultBlocked && isProtocolAddr(a, ma.P_IP6) { + return false + } + return true + }, + ) +} + +// RecordResult updates the state of the relevant `blackHoleFilter`s for addr +func (d *blackHoleDetector) RecordResult(addr ma.Multiaddr, success bool) { + if !manet.IsPublicAddr(addr) { + return + } + if d.udp != nil && isProtocolAddr(addr, ma.P_UDP) { + d.udp.RecordResult(success) + } + if d.ipv6 != nil && isProtocolAddr(addr, ma.P_IP6) { + d.ipv6.RecordResult(success) + } +} + +// blackHoleConfig is the config used for black hole detection +type blackHoleConfig struct { + // Enabled enables black hole detection + Enabled bool + // N is the size of the sliding window used to evaluate black hole state + N int + // MinSuccesses is the minimum number of successes out of N required to not + // block requests + MinSuccesses int +} + +func newBlackHoleDetector(udpConfig, ipv6Config blackHoleConfig, mt MetricsTracer) *blackHoleDetector { + d := &blackHoleDetector{} + + if udpConfig.Enabled { + d.udp = &blackHoleFilter{ + n: udpConfig.N, + minSuccesses: udpConfig.MinSuccesses, + name: "UDP", + metricsTracer: mt, + } + } + + if ipv6Config.Enabled { + d.ipv6 = &blackHoleFilter{ + n: ipv6Config.N, + minSuccesses: ipv6Config.MinSuccesses, + name: "IPv6", + metricsTracer: mt, + } + } + return d +} diff --git a/p2p/net/swarm/black_hole_detector_test.go b/p2p/net/swarm/black_hole_detector_test.go new file mode 100644 index 0000000000..7b10fc88a6 --- /dev/null +++ b/p2p/net/swarm/black_hole_detector_test.go @@ -0,0 +1,183 @@ +package swarm + +import ( + "fmt" + "testing" + + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestBlackHoleFilterReset(t *testing.T) { + n := 10 + bhf := &blackHoleFilter{n: n, minSuccesses: 2, name: "test"} + var i = 0 + // calls up to n should be probing + for i = 1; i <= n; i++ { + if bhf.HandleRequest() != blackHoleResultProbing { + t.Fatalf("expected calls up to n to be probes") + } + bhf.RecordResult(false) + } + + // after threshold calls every nth call should be a probe + for i = n + 1; i < 42; i++ { + result := bhf.HandleRequest() + if (i%n == 0 && result != blackHoleResultProbing) || (i%n != 0 && result != blackHoleResultBlocked) { + t.Fatalf("expected every nth dial to be a probe") + } + } + + bhf.RecordResult(true) + // check if calls up to n are probes again + for i = 0; i < n; i++ { + if bhf.HandleRequest() != blackHoleResultProbing { + t.Fatalf("expected black hole detector state to reset after success") + } + bhf.RecordResult(false) + } + + // next call should be blocked + if bhf.HandleRequest() != blackHoleResultBlocked { + t.Fatalf("expected dial to be blocked") + } +} + +func TestBlackHoleFilterSuccessFraction(t *testing.T) { + n := 10 + tests := []struct { + minSuccesses, successes int + result blackHoleResult + }{ + {minSuccesses: 5, successes: 5, result: blackHoleResultAllowed}, + {minSuccesses: 3, successes: 3, result: blackHoleResultAllowed}, + {minSuccesses: 5, successes: 4, result: blackHoleResultBlocked}, + {minSuccesses: 5, successes: 7, result: blackHoleResultAllowed}, + {minSuccesses: 3, successes: 1, result: blackHoleResultBlocked}, + {minSuccesses: 0, successes: 0, result: blackHoleResultAllowed}, + {minSuccesses: 10, successes: 10, result: blackHoleResultAllowed}, + } + for i, tc := range tests { + t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) { + bhf := blackHoleFilter{n: n, minSuccesses: tc.minSuccesses} + for i := 0; i < tc.successes; i++ { + bhf.RecordResult(true) + } + for i := 0; i < n-tc.successes; i++ { + bhf.RecordResult(false) + } + got := bhf.HandleRequest() + if got != tc.result { + t.Fatalf("expected %d got %d", tc.result, got) + } + }) + } +} + +func TestBlackHoleDetectorInApplicableAddress(t *testing.T) { + udpConfig := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5} + ipv6Config := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5} + bhd := newBlackHoleDetector(udpConfig, ipv6Config, nil) + addrs := []ma.Multiaddr{ + ma.StringCast("/ip4/1.2.3.4/tcp/1234"), + ma.StringCast("/ip4/1.2.3.4/tcp/1233"), + ma.StringCast("/ip6/::1/udp/1234/quic-v1"), + ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1"), + } + for i := 0; i < 1000; i++ { + filteredAddrs := bhd.FilterAddrs(addrs) + require.ElementsMatch(t, addrs, filteredAddrs) + for j := 0; j < len(addrs); j++ { + bhd.RecordResult(addrs[j], false) + } + } +} + +func TestBlackHoleDetectorUDPDisabled(t *testing.T) { + ipv6Config := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5} + bhd := newBlackHoleDetector(blackHoleConfig{Enabled: false}, ipv6Config, nil) + publicAddr := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1") + privAddr := ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1") + for i := 0; i < 100; i++ { + bhd.RecordResult(publicAddr, false) + } + addrs := []ma.Multiaddr{publicAddr, privAddr} + require.ElementsMatch(t, addrs, bhd.FilterAddrs(addrs)) +} + +func TestBlackHoleDetectorIPv6Disabled(t *testing.T) { + udpConfig := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5} + bhd := newBlackHoleDetector(udpConfig, blackHoleConfig{Enabled: false}, nil) + publicAddr := ma.StringCast("/ip6/1::1/tcp/1234") + privAddr := ma.StringCast("/ip6/::1/tcp/1234") + addrs := []ma.Multiaddr{publicAddr, privAddr} + for i := 0; i < 100; i++ { + bhd.RecordResult(publicAddr, false) + } + require.ElementsMatch(t, addrs, bhd.FilterAddrs(addrs)) +} + +func TestBlackHoleDetectorProbes(t *testing.T) { + bhd := &blackHoleDetector{ + udp: &blackHoleFilter{n: 2, minSuccesses: 1, name: "udp"}, + ipv6: &blackHoleFilter{n: 3, minSuccesses: 1, name: "ipv6"}, + } + udp6Addr := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + addrs := []ma.Multiaddr{udp6Addr} + for i := 0; i < 3; i++ { + bhd.RecordResult(udp6Addr, false) + } + for i := 1; i < 100; i++ { + filteredAddrs := bhd.FilterAddrs(addrs) + if i%2 == 0 || i%3 == 0 { + if len(filteredAddrs) == 0 { + t.Fatalf("expected probe to be allowed irrespective of the state of other black hole filter") + } + } else { + if len(filteredAddrs) != 0 { + t.Fatalf("expected dial to be blocked %s", filteredAddrs) + } + } + } + +} + +func TestBlackHoleDetectorAddrFiltering(t *testing.T) { + udp6Pub := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + udp6Pri := ma.StringCast("/ip6/::1/udp/1234/quic-v1") + upd4Pub := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1") + udp4Pri := ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1") + tcp6Pub := ma.StringCast("/ip6/1::1/tcp/1234/quic-v1") + tcp6Pri := ma.StringCast("/ip6/::1/tcp/1234/quic-v1") + tcp4Pub := ma.StringCast("/ip4/1.2.3.4/tcp/1234/quic-v1") + tcp4Pri := ma.StringCast("/ip4/192.168.1.5/tcp/1234/quic-v1") + + makeBHD := func(udpBlocked, ipv6Blocked bool) *blackHoleDetector { + bhd := &blackHoleDetector{ + udp: &blackHoleFilter{n: 100, minSuccesses: 10, name: "udp"}, + ipv6: &blackHoleFilter{n: 100, minSuccesses: 10, name: "ipv6"}, + } + for i := 0; i < 100; i++ { + bhd.RecordResult(upd4Pub, !udpBlocked) + } + for i := 0; i < 100; i++ { + bhd.RecordResult(tcp6Pub, !ipv6Blocked) + } + return bhd + } + + allInput := []ma.Multiaddr{udp6Pub, udp6Pri, upd4Pub, udp4Pri, tcp6Pub, tcp6Pri, + tcp4Pub, tcp4Pri} + + udpBlockedOutput := []ma.Multiaddr{udp6Pri, udp4Pri, tcp6Pub, tcp6Pri, tcp4Pub, tcp4Pri} + bhd := makeBHD(true, false) + require.ElementsMatch(t, udpBlockedOutput, bhd.FilterAddrs(allInput)) + + ip6BlockedOutput := []ma.Multiaddr{udp6Pri, upd4Pub, udp4Pri, tcp6Pri, tcp4Pub, tcp4Pri} + bhd = makeBHD(false, true) + require.ElementsMatch(t, ip6BlockedOutput, bhd.FilterAddrs(allInput)) + + bothBlockedOutput := []ma.Multiaddr{udp6Pri, udp4Pri, tcp6Pri, tcp4Pub, tcp4Pri} + bhd = makeBHD(true, true) + require.ElementsMatch(t, bothBlockedOutput, bhd.FilterAddrs(allInput)) +} diff --git a/p2p/net/swarm/clock.go b/p2p/net/swarm/clock.go new file mode 100644 index 0000000000..6b63ac9c87 --- /dev/null +++ b/p2p/net/swarm/clock.go @@ -0,0 +1,49 @@ +package swarm + +import "time" + +// InstantTimer is a timer that triggers at some instant rather than some duration +type InstantTimer interface { + Reset(d time.Time) bool + Stop() bool + Ch() <-chan time.Time +} + +// Clock is a clock that can create timers that trigger at some +// instant rather than some duration +type Clock interface { + Now() time.Time + Since(t time.Time) time.Duration + InstantTimer(when time.Time) InstantTimer +} + +type RealTimer struct{ t *time.Timer } + +var _ InstantTimer = (*RealTimer)(nil) + +func (t RealTimer) Ch() <-chan time.Time { + return t.t.C +} + +func (t RealTimer) Reset(d time.Time) bool { + return t.t.Reset(time.Until(d)) +} + +func (t RealTimer) Stop() bool { + return t.t.Stop() +} + +type RealClock struct{} + +var _ Clock = RealClock{} + +func (RealClock) Now() time.Time { + return time.Now() +} +func (RealClock) Since(t time.Time) time.Duration { + return time.Since(t) +} +func (RealClock) InstantTimer(when time.Time) InstantTimer { + t := time.NewTimer(time.Until(when)) + return &RealTimer{t} +} diff --git a/p2p/net/swarm/dial_ranker.go b/p2p/net/swarm/dial_ranker.go new file mode 100644 index 0000000000..3725884e2e --- /dev/null +++ b/p2p/net/swarm/dial_ranker.go @@ -0,0 +1,199 @@ +package swarm + +import ( + "sort" + "strconv" + "time" + + "github.com/libp2p/go-libp2p/core/network" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +// The 250ms value is from happy eyeballs RFC 8305. This is a rough estimate of 1 RTT +const ( + // duration by which TCP dials are delayed relative to the last QUIC dial + PublicTCPDelay = 250 * time.Millisecond + PrivateTCPDelay = 30 * time.Millisecond + + // duration by which QUIC dials are delayed relative to previous QUIC dial + PublicQUICDelay = 250 * time.Millisecond + PrivateQUICDelay = 30 * time.Millisecond + + // RelayDelay is the duration by which relay dials are delayed relative to direct addresses + RelayDelay = 500 * time.Millisecond +) + +// NoDelayDialRanker ranks addresses with no delay. This is useful for simultaneous connect requests. +func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { + return getAddrDelay(addrs, 0, 0, 0) +} + +// DefaultDialRanker determines the ranking of outgoing connection attempts. +// +// Addresses are grouped into three distinct groups: +// +// - private addresses (localhost and local networks (RFC 1918)) +// - public addresses +// - relay addresses +// +// Within each group, the addresses are ranked according to the ranking logic described below. +// We then dial addresses according to this ranking, with short timeouts applied between dial attempts. +// This ranking logic dramatically reduces the number of simultaneous dial attempts, while introducing +// no additional latency in the vast majority of cases. +// +// Private and public address groups are dialed in parallel. +// Dialing relay addresses is delayed by 500 ms, if we have any non-relay alternatives. +// +// Within each group (private, public, relay addresses) we apply the following ranking logic: +// +// 1. If both IPv6 QUIC and IPv4 QUIC addresses are present, we do a Happy Eyeballs RFC 8305 style ranking. +// First dial the IPv6 QUIC address with the lowest port. After this we dial the IPv4 QUIC address with +// the lowest port delayed by 250ms (PublicQUICDelay) for public addresses, and 30ms (PrivateQUICDelay) +// for local addresses. After this we dial all the rest of the addresses delayed by 250ms (PublicQUICDelay) +// for public addresses, and 30ms (PrivateQUICDelay) for local addresses. +// 2. If only one of QUIC IPv6 or QUIC IPv4 addresses are present, dial the QUIC address with the lowest port +// first. After this we dial the rest of the QUIC addresses delayed by 250ms (PublicQUICDelay) for public +// addresses, and 30ms (PrivateQUICDelay) for local addresses. +// 3. If a QUIC or WebTransport address is present, TCP addresses dials are delayed relative to the last QUIC dial: +// We prefer to end up with a QUIC connection. For public addresses, the delay introduced is 250ms (PublicTCPDelay), +// and for private addresses 30ms (PrivateTCPDelay). +// +// We dial lowest ports first for QUIC addresses as they are more likely to be the listen port. +func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { + relay, addrs := filterAddrs(addrs, isRelayAddr) + pvt, addrs := filterAddrs(addrs, manet.IsPrivateAddr) + public, addrs := filterAddrs(addrs, func(a ma.Multiaddr) bool { return isProtocolAddr(a, ma.P_IP4) || isProtocolAddr(a, ma.P_IP6) }) + + var relayOffset time.Duration + if len(public) > 0 { + // if there is a public direct address available delay relay dials + relayOffset = RelayDelay + } + + res := make([]network.AddrDelay, 0, len(addrs)) + for i := 0; i < len(addrs); i++ { + res = append(res, network.AddrDelay{Addr: addrs[i], Delay: 0}) + } + + res = append(res, getAddrDelay(pvt, PrivateTCPDelay, PrivateQUICDelay, 0)...) + res = append(res, getAddrDelay(public, PublicTCPDelay, PublicQUICDelay, 0)...) + res = append(res, getAddrDelay(relay, PublicTCPDelay, PublicQUICDelay, relayOffset)...) + return res +} + +// getAddrDelay ranks a group of addresses according to the ranking logic explained in +// documentation for defaultDialRanker. +// offset is used to delay all addresses by a fixed duration. This is useful for delaying all relay +// addresses relative to direct addresses. +func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.Duration, + offset time.Duration) []network.AddrDelay { + + sort.Slice(addrs, func(i, j int) bool { return score(addrs[i]) < score(addrs[j]) }) + + // If the first address is (QUIC, IPv6), make the second address (QUIC, IPv4). + happyEyeballs := false + if len(addrs) > 0 { + if isQUICAddr(addrs[0]) && isProtocolAddr(addrs[0], ma.P_IP6) { + for i := 1; i < len(addrs); i++ { + if isQUICAddr(addrs[i]) && isProtocolAddr(addrs[i], ma.P_IP4) { + // make IPv4 address the second element + if i > 1 { + a := addrs[i] + copy(addrs[2:], addrs[1:i]) + addrs[1] = a + } + happyEyeballs = true + break + } + } + } + } + + res := make([]network.AddrDelay, 0, len(addrs)) + + var totalTCPDelay time.Duration + for i, addr := range addrs { + var delay time.Duration + switch { + case isQUICAddr(addr): + // For QUIC addresses we dial an IPv6 address, then after quicDelay an IPv4 + // address, then after quicDelay we dial rest of the addresses. + if i == 1 { + delay = quicDelay + } + if i > 1 && happyEyeballs { + delay = 2 * quicDelay + } else if i > 1 { + delay = quicDelay + } + totalTCPDelay = delay + tcpDelay + case isProtocolAddr(addr, ma.P_TCP): + delay = totalTCPDelay + } + res = append(res, network.AddrDelay{Addr: addr, Delay: offset + delay}) + } + return res +} + +// score scores a multiaddress for dialing delay. Lower is better. +// The lower 16 bits of the result are the port. Low ports are ranked higher because they're +// more likely to be listen addresses. +// The addresses are ranked as: +// QUICv1 IPv6 > QUICdraft29 IPv6 > QUICv1 IPv4 > QUICdraft29 IPv4 > +// WebTransport IPv6 > WebTransport IPv4 > TCP IPv6 > TCP IPv4 +func score(a ma.Multiaddr) int { + ip4Weight := 0 + if isProtocolAddr(a, ma.P_IP4) { + ip4Weight = 1 << 18 + } + + if _, err := a.ValueForProtocol(ma.P_WEBTRANSPORT); err == nil { + p, _ := a.ValueForProtocol(ma.P_UDP) + pi, _ := strconv.Atoi(p) + return ip4Weight + (1 << 19) + pi + } + if _, err := a.ValueForProtocol(ma.P_QUIC); err == nil { + p, _ := a.ValueForProtocol(ma.P_UDP) + pi, _ := strconv.Atoi(p) + return ip4Weight + pi + (1 << 17) + } + if _, err := a.ValueForProtocol(ma.P_QUIC_V1); err == nil { + p, _ := a.ValueForProtocol(ma.P_UDP) + pi, _ := strconv.Atoi(p) + return ip4Weight + pi + } + if p, err := a.ValueForProtocol(ma.P_TCP); err == nil { + pi, _ := strconv.Atoi(p) + return ip4Weight + pi + (1 << 20) + } + return (1 << 30) +} + +func isProtocolAddr(a ma.Multiaddr, p int) bool { + found := false + ma.ForEach(a, func(c ma.Component) bool { + if c.Protocol().Code == p { + found = true + return false + } + return true + }) + return found +} + +func isQUICAddr(a ma.Multiaddr) bool { + return isProtocolAddr(a, ma.P_QUIC) || isProtocolAddr(a, ma.P_QUIC_V1) +} + +// filterAddrs filters an address slice in place +func filterAddrs(addrs []ma.Multiaddr, f func(a ma.Multiaddr) bool) (filtered, rest []ma.Multiaddr) { + j := 0 + for i := 0; i < len(addrs); i++ { + if f(addrs[i]) { + addrs[i], addrs[j] = addrs[j], addrs[i] + j++ + } + } + return addrs[:j], addrs[j:] +} diff --git a/p2p/net/swarm/dial_ranker_test.go b/p2p/net/swarm/dial_ranker_test.go new file mode 100644 index 0000000000..60fbfabbfb --- /dev/null +++ b/p2p/net/swarm/dial_ranker_test.go @@ -0,0 +1,280 @@ +package swarm + +import ( + "fmt" + "sort" + "testing" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/test" + ma "github.com/multiformats/go-multiaddr" +) + +func sortAddrDelays(addrDelays []network.AddrDelay) { + sort.Slice(addrDelays, func(i, j int) bool { + if addrDelays[i].Delay == addrDelays[j].Delay { + return addrDelays[i].Addr.String() < addrDelays[j].Addr.String() + } + return addrDelays[i].Delay < addrDelays[j].Delay + }) +} + +func TestNoDelayDialRanker(t *testing.T) { + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + q3v1 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") + q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic") + t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") + + testCase := []struct { + name string + addrs []ma.Multiaddr + output []network.AddrDelay + }{ + { + name: "quic+webtransport filtered when quicv1", + addrs: []ma.Multiaddr{q1, q2, q3, q4, q1v1, q2v1, q3v1, wt1, t1}, + output: []network.AddrDelay{ + {Addr: q1, Delay: 0}, + {Addr: q2, Delay: 0}, + {Addr: q3, Delay: 0}, + {Addr: q4, Delay: 0}, + {Addr: q1v1, Delay: 0}, + {Addr: q2v1, Delay: 0}, + {Addr: q3v1, Delay: 0}, + {Addr: wt1, Delay: 0}, + {Addr: t1, Delay: 0}, + }, + }, + } + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res := NoDelayDialRanker(tc.addrs) + if len(res) != len(tc.output) { + log.Errorf("expected %s got %s", tc.output, res) + t.Errorf("expected elems: %d got: %d", len(tc.output), len(res)) + } + sortAddrDelays(res) + sortAddrDelays(tc.output) + for i := 0; i < len(tc.output); i++ { + if !tc.output[i].Addr.Equal(res[i].Addr) || tc.output[i].Delay != res[i].Delay { + t.Fatalf("expected %+v got %+v", tc.output, res) + } + } + }) + } +} + +func TestDelayRankerQUICDelay(t *testing.T) { + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + q3v1 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") + q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic") + + q1v16 := ma.StringCast("/ip6/1::2/udp/1/quic-v1") + q2v16 := ma.StringCast("/ip6/1::2/udp/2/quic-v1") + q3v16 := ma.StringCast("/ip6/1::2/udp/3/quic-v1") + + testCase := []struct { + name string + addrs []ma.Multiaddr + output []network.AddrDelay + }{ + { + name: "quic-ipv4", + addrs: []ma.Multiaddr{q1, q2, q3, q4}, + output: []network.AddrDelay{ + {Addr: q1, Delay: 0}, + {Addr: q2, Delay: PublicQUICDelay}, + {Addr: q3, Delay: PublicQUICDelay}, + {Addr: q4, Delay: PublicQUICDelay}, + }, + }, + { + name: "quic-ipv6", + addrs: []ma.Multiaddr{q1v16, q2v16, q3v16}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q2v16, Delay: PublicQUICDelay}, + {Addr: q3v16, Delay: PublicQUICDelay}, + }, + }, + { + name: "quic-ip4-ip6", + addrs: []ma.Multiaddr{q1, q1v16, q2v1, q3, q4}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q2v1, Delay: PublicQUICDelay}, + {Addr: q1, Delay: 2 * PublicQUICDelay}, + {Addr: q3, Delay: 2 * PublicQUICDelay}, + {Addr: q4, Delay: 2 * PublicQUICDelay}, + }, + }, + { + name: "quic-quic-v1-webtransport", + addrs: []ma.Multiaddr{q1v16, q1, q2, q3, q4, q1v1, q2v1, q3v1, wt1}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q1v1, Delay: PublicQUICDelay}, + {Addr: q2v1, Delay: 2 * PublicQUICDelay}, + {Addr: q3v1, Delay: 2 * PublicQUICDelay}, + {Addr: q1, Delay: 2 * PublicQUICDelay}, + {Addr: q2, Delay: 2 * PublicQUICDelay}, + {Addr: q3, Delay: 2 * PublicQUICDelay}, + {Addr: q4, Delay: 2 * PublicQUICDelay}, + {Addr: wt1, Delay: 2 * PublicQUICDelay}, + }, + }, + { + name: "wt-ranking", + addrs: []ma.Multiaddr{q1v16, q2v16, q3v16, q2, wt1}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q2, Delay: PublicQUICDelay}, + {Addr: wt1, Delay: 2 * PublicQUICDelay}, + {Addr: q2v16, Delay: 2 * PublicQUICDelay}, + {Addr: q3v16, Delay: 2 * PublicQUICDelay}, + }, + }, + } + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res := DefaultDialRanker(tc.addrs) + if len(res) != len(tc.output) { + log.Errorf("expected %s got %s", tc.output, res) + t.Errorf("expected elems: %d got: %d", len(tc.output), len(res)) + } + sortAddrDelays(res) + sortAddrDelays(tc.output) + for i := 0; i < len(tc.output); i++ { + if !tc.output[i].Addr.Equal(res[i].Addr) || tc.output[i].Delay != res[i].Delay { + t.Fatalf("expected %+v got %+v", tc.output, res) + } + } + }) + } +} + +func TestDelayRankerTCPDelay(t *testing.T) { + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + + q1v16 := ma.StringCast("/ip6/1::2/udp/1/quic-v1") + q2v16 := ma.StringCast("/ip6/1::2/udp/2/quic-v1") + q3v16 := ma.StringCast("/ip6/1::2/udp/3/quic-v1") + + t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") + t1v6 := ma.StringCast("/ip6/1::2/tcp/1") + t2 := ma.StringCast("/ip4/1.2.3.4/tcp/2") + + testCase := []struct { + name string + addrs []ma.Multiaddr + output []network.AddrDelay + }{ + { + name: "quic-with-tcp-ip6-ip4", + addrs: []ma.Multiaddr{q1, q1v1, q1v16, q2v16, q3v16, q2v1, t1, t2}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q1v1, Delay: PublicQUICDelay}, + {Addr: q1, Delay: 2 * PublicQUICDelay}, + {Addr: q2v16, Delay: 2 * PublicQUICDelay}, + {Addr: q3v16, Delay: 2 * PublicQUICDelay}, + {Addr: q2v1, Delay: 2 * PublicQUICDelay}, + {Addr: t1, Delay: 3 * PublicQUICDelay}, + {Addr: t2, Delay: 3 * PublicQUICDelay}, + }, + }, + { + name: "quic-ip4-with-tcp", + addrs: []ma.Multiaddr{q1, q2, q3, t1, t2, t1v6}, + output: []network.AddrDelay{ + {Addr: q1, Delay: 0}, + {Addr: q2, Delay: PublicQUICDelay}, + {Addr: q3, Delay: PublicQUICDelay}, + {Addr: t1, Delay: PublicQUICDelay + PublicTCPDelay}, + {Addr: t2, Delay: PublicQUICDelay + PublicTCPDelay}, + {Addr: t1v6, Delay: PublicQUICDelay + PublicTCPDelay}, + }, + }, + { + name: "tcp-ip4-ip6", + addrs: []ma.Multiaddr{t1, t2, t1v6}, + output: []network.AddrDelay{ + {Addr: t1v6, Delay: 0}, + {Addr: t1, Delay: 0}, + {Addr: t2, Delay: 0}, + }, + }, + } + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res := DefaultDialRanker(tc.addrs) + if len(res) != len(tc.output) { + log.Errorf("expected %s got %s", tc.output, res) + t.Errorf("expected elems: %d got: %d", len(tc.output), len(res)) + } + sortAddrDelays(res) + sortAddrDelays(tc.output) + for i := 0; i < len(tc.output); i++ { + if !tc.output[i].Addr.Equal(res[i].Addr) || tc.output[i].Delay != res[i].Delay { + t.Fatalf("expected %+v got %+v", tc.output, res) + } + } + }) + } +} + +func TestDelayRankerRelay(t *testing.T) { + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + + pid := test.RandPeerIDFatal(t) + r1 := ma.StringCast(fmt.Sprintf("/ip4/1.2.3.4/tcp/1/p2p-circuit/p2p/%s", pid)) + r2 := ma.StringCast(fmt.Sprintf("/ip4/1.2.3.4/udp/1/quic/p2p-circuit/p2p/%s", pid)) + + testCase := []struct { + name string + addrs []ma.Multiaddr + output []network.AddrDelay + }{ + { + name: "relay address delayed", + addrs: []ma.Multiaddr{q1, q2, r1, r2}, + output: []network.AddrDelay{ + {Addr: q1, Delay: 0}, + {Addr: q2, Delay: PublicQUICDelay}, + {Addr: r2, Delay: RelayDelay}, + {Addr: r1, Delay: PublicTCPDelay + RelayDelay}, + }, + }, + } + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res := DefaultDialRanker(tc.addrs) + if len(res) != len(tc.output) { + log.Errorf("expected %s got %s", tc.output, res) + t.Errorf("expected elems: %d got: %d", len(tc.output), len(res)) + } + sortAddrDelays(res) + sortAddrDelays(tc.output) + for i := 0; i < len(tc.output); i++ { + if !tc.output[i].Addr.Equal(res[i].Addr) || tc.output[i].Delay != res[i].Delay { + t.Fatalf("expected %+v got %+v", tc.output, res) + } + } + }) + } +} diff --git a/p2p/net/swarm/dial_worker.go b/p2p/net/swarm/dial_worker.go index ba7ba87d4b..0334ac863e 100644 --- a/p2p/net/swarm/dial_worker.go +++ b/p2p/net/swarm/dial_worker.go @@ -2,13 +2,14 @@ package swarm import ( "context" + "math" "sync" + "time" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" ) // ///////////////////////////////////////////////////////////////////////////////// @@ -16,77 +17,159 @@ import ( // TODO explain how all this works // //////////////////////////////////////////////////////////////////////////////// +// dialRequest is structure used to request dials to the peer associated with a +// worker loop type dialRequest struct { - ctx context.Context + // ctx is the context that may be used for the request + // if another concurrent request is made, any of the concurrent request's ctx may be used for + // dials to the peer's addresses + // ctx for simultaneous connect requests have higher priority than normal requests + ctx context.Context + // resch is the channel used to send the response for this query resch chan dialResponse } +// dialResponse is the response sent to dialRequests on the request's resch channel type dialResponse struct { + // conn is the connection to the peer on success conn *Conn - err error + // err is the error in dialing the peer + // nil on connection success + err error } +// pendRequest is used to track progress on a dialRequest. type pendRequest struct { - req dialRequest // the original request - err *DialError // dial error accumulator - addrs map[string]struct{} // pending address to dial. The key is a multiaddr + // req is the original dialRequest + req dialRequest + // err comprises errors of all failed dials + err *DialError + // addrs are the addresses on which we are waiting for pending dials + // At the time of creation addrs is initialised to all the addresses of the peer. On a failed dial, + // the addr is removed from the map and err is updated. On a successful dial, the dialRequest is + // completed and response is sent with the connection + addrs map[string]struct{} } +// addrDial tracks dials to a particular multiaddress. type addrDial struct { - addr ma.Multiaddr - ctx context.Context - conn *Conn - err error + // addr is the address dialed + addr ma.Multiaddr + // ctx is the context used for dialing the address + ctx context.Context + // conn is the established connection on success + conn *Conn + // err is the err on dialing the address + err error + // requests is the list of pendRequests interested in this dial + // the value in the slice is the request number assigned to this request by the dialWorker requests []int + // dialed indicates whether we have triggered the dial to the address + dialed bool + // createdAt is the time this struct was created + createdAt time.Time + // dialRankingDelay is the delay in dialing this address introduced by the ranking logic + dialRankingDelay time.Duration } +// dialWorker synchronises concurrent dials to a peer. It ensures that we make at most one dial to a +// peer's address type dialWorker struct { - s *Swarm - peer peer.ID - reqch <-chan dialRequest - reqno int - requests map[int]*pendRequest - pending map[string]*addrDial // pending addresses to dial. The key is a multiaddr - resch chan dialResult + s *Swarm + peer peer.ID + // reqch is used to send dial requests to the worker. close reqch to end the worker loop + reqch <-chan dialRequest + // reqno is the request number used to track different dialRequests for a peer. + // Each incoming request is assigned a reqno. This reqno is used in pendingRequests and in + // addrDial objects in trackedDials to track this request + reqno int + // pendingRequests maps reqno to the pendRequest object for a dialRequest + pendingRequests map[int]*pendRequest + // trackedDials tracks dials to the peers addresses. An entry here is used to ensure that + // we dial an address at most once + trackedDials map[string]*addrDial + // resch is used to receive response for dials to the peers addresses. + resch chan dialResult connected bool // true when a connection has been successfully established - nextDial []ma.Multiaddr - - // ready when we have more addresses to dial (nextDial is not empty) - triggerDial <-chan struct{} - // for testing wg sync.WaitGroup + cl Clock } -func newDialWorker(s *Swarm, p peer.ID, reqch <-chan dialRequest) *dialWorker { +func newDialWorker(s *Swarm, p peer.ID, reqch <-chan dialRequest, cl Clock) *dialWorker { + if cl == nil { + cl = RealClock{} + } return &dialWorker{ - s: s, - peer: p, - reqch: reqch, - requests: make(map[int]*pendRequest), - pending: make(map[string]*addrDial), - resch: make(chan dialResult), + s: s, + peer: p, + reqch: reqch, + pendingRequests: make(map[int]*pendRequest), + trackedDials: make(map[string]*addrDial), + resch: make(chan dialResult), + cl: cl, } } +// loop implements the core dial worker loop. Requests are received on w.reqch. +// The loop exits when w.reqch is closed. func (w *dialWorker) loop() { w.wg.Add(1) defer w.wg.Done() defer w.s.limiter.clearAllPeerDials(w.peer) - // used to signal readiness to dial and completion of the dial - ready := make(chan struct{}) - close(ready) + // dq is used to pace dials to different addresses of the peer + dq := newDialQueue() + // dialsInFlight is the number of dials in flight. + dialsInFlight := 0 + + startTime := w.cl.Now() + // dialTimer is the dialTimer used to trigger dials + dialTimer := w.cl.InstantTimer(startTime.Add(math.MaxInt64)) + timerRunning := true + // scheduleNextDial updates timer for triggering the next dial + scheduleNextDial := func() { + if timerRunning && !dialTimer.Stop() { + <-dialTimer.Ch() + } + timerRunning = false + if dq.len() > 0 { + if dialsInFlight == 0 && !w.connected { + // if there are no dials in flight, trigger the next dials immediately + dialTimer.Reset(startTime) + } else { + dialTimer.Reset(startTime.Add(dq.top().Delay)) + } + timerRunning = true + } + } + // totalDials is used to track number of dials made by this worker for metrics + totalDials := 0 loop: for { + // The loop has three parts + // 1. Input requests are received on w.reqch. If a suitable connection is not available we create + // a pendRequest object to track the dialRequest and add the addresses to dq. + // 2. Addresses from the dialQueue are dialed at appropriate time intervals depending on delay logic. + // We are notified of the completion of these dials on w.resch. + // 3. Responses for dials are received on w.resch. On receiving a response, we updated the pendRequests + // interested in dials on this address. + select { case req, ok := <-w.reqch: if !ok { + if w.s.metricsTracer != nil { + w.s.metricsTracer.DialCompleted(w.connected, totalDials) + } return } + // We have received a new request. If we do not have a suitable connection, + // track this dialRequest with a pendRequest. + // Enqueue the peer's addresses relevant to this request in dq and + // track dials to the addresses relevant to this request. c, err := w.s.bestAcceptableConnToPeer(req.ctx, w.peer) if c != nil || err != nil { @@ -100,29 +183,34 @@ loop: continue loop } - // at this point, len(addrs) > 0 or else it would be error from addrsForDial - // ranke them to process in order - addrs = w.rankAddrs(addrs) + // get the delays to dial these addrs from the swarms dialRanker + simConnect, _, _ := network.GetSimultaneousConnect(req.ctx) + addrRanking := w.rankAddrs(addrs, simConnect) + addrDelay := make(map[string]time.Duration, len(addrRanking)) // create the pending request object pr := &pendRequest{ req: req, err: &DialError{Peer: w.peer}, - addrs: make(map[string]struct{}), + addrs: make(map[string]struct{}, len(addrRanking)), } - for _, a := range addrs { - pr.addrs[string(a.Bytes())] = struct{}{} + for _, adelay := range addrRanking { + pr.addrs[string(adelay.Addr.Bytes())] = struct{}{} + addrDelay[string(adelay.Addr.Bytes())] = adelay.Delay } - // check if any of the addrs has been successfully dialed and accumulate - // errors from complete dials while collecting new addrs to dial/join + // Check if dials to any of the addrs have completed already + // If they have errored, record the error in pr. If they have succeeded, + // respond with the connection. + // If they are pending, add them to tojoin. + // If we haven't seen any of the addresses before, add them to todial. var todial []ma.Multiaddr var tojoin []*addrDial - for _, a := range addrs { - ad, ok := w.pending[string(a.Bytes())] + for _, adelay := range addrRanking { + ad, ok := w.trackedDials[string(adelay.Addr.Bytes())] if !ok { - todial = append(todial, a) + todial = append(todial, adelay.Addr) continue } @@ -134,8 +222,8 @@ loop: if ad.err != nil { // dial to this addr errored, accumulate the error - pr.err.recordErr(a, ad.err) - delete(pr.addrs, string(a.Bytes())) + pr.err.recordErr(ad.addr, ad.err) + delete(pr.addrs, string(ad.addr.Bytes())) continue } @@ -149,50 +237,91 @@ loop: continue loop } - // the request has some pending or new dials, track it and schedule new dials + // The request has some pending or new dials. We assign this request a request number. + // This value of w.reqno is used to track this request in all the structures w.reqno++ - w.requests[w.reqno] = pr + w.pendingRequests[w.reqno] = pr for _, ad := range tojoin { - if simConnect, isClient, reason := network.GetSimultaneousConnect(req.ctx); simConnect { - if simConnect, _, _ := network.GetSimultaneousConnect(ad.ctx); !simConnect { - ad.ctx = network.WithSimultaneousConnect(ad.ctx, isClient, reason) + if !ad.dialed { + // we haven't dialed this address. update the ad.ctx to have simultaneous connect values + // set correctly + if simConnect, isClient, reason := network.GetSimultaneousConnect(req.ctx); simConnect { + if simConnect, _, _ := network.GetSimultaneousConnect(ad.ctx); !simConnect { + ad.ctx = network.WithSimultaneousConnect(ad.ctx, isClient, reason) + // update the element in dq to use the simultaneous connect delay. + dq.Add(network.AddrDelay{ + Addr: ad.addr, + Delay: addrDelay[string(ad.addr.Bytes())], + }) + } } } + // add the request to the addrDial ad.requests = append(ad.requests, w.reqno) } if len(todial) > 0 { + now := time.Now() + // these are new addresses, track them and add them to dq for _, a := range todial { - w.pending[string(a.Bytes())] = &addrDial{addr: a, ctx: req.ctx, requests: []int{w.reqno}} + w.trackedDials[string(a.Bytes())] = &addrDial{ + addr: a, + ctx: req.ctx, + requests: []int{w.reqno}, + createdAt: now, + } + dq.Add(network.AddrDelay{Addr: a, Delay: addrDelay[string(a.Bytes())]}) } - - w.nextDial = append(w.nextDial, todial...) - w.nextDial = w.rankAddrs(w.nextDial) - - // trigger a new dial now to account for the new addrs we added - w.triggerDial = ready } - - case <-w.triggerDial: - for _, addr := range w.nextDial { + // setup dialTimer for updates to dq + scheduleNextDial() + + case <-dialTimer.Ch(): + // It's time to dial the next batch of addresses. + // We don't check the delay of the addresses received from the queue here + // because if the timer triggered before the delay, it means that all + // the inflight dials have errored and we should dial the next batch of + // addresses + now := time.Now() + for _, adelay := range dq.NextBatch() { // spawn the dial - ad := w.pending[string(addr.Bytes())] - err := w.s.dialNextAddr(ad.ctx, w.peer, addr, w.resch) + ad, ok := w.trackedDials[string(adelay.Addr.Bytes())] + if !ok { + log.Errorf("SWARM BUG: no entry for address %s in trackedDials", adelay.Addr) + continue + } + ad.dialed = true + ad.dialRankingDelay = now.Sub(ad.createdAt) + err := w.s.dialNextAddr(ad.ctx, w.peer, ad.addr, w.resch) if err != nil { + // Errored without attempting a dial. This happens in case of + // backoff or black hole. w.dispatchError(ad, err) + } else { + // the dial was successful. update inflight dials + dialsInFlight++ + totalDials++ } } - - w.nextDial = nil - w.triggerDial = nil + timerRunning = false + // schedule more dials + scheduleNextDial() case res := <-w.resch: - if res.Conn != nil { - w.connected = true - } + // A dial to an address has completed. + // Update all requests waiting on this address. On success, complete the request. + // On error, record the error - ad := w.pending[string(res.Addr.Bytes())] + dialsInFlight-- + ad, ok := w.trackedDials[string(res.Addr.Bytes())] + if !ok { + log.Errorf("SWARM BUG: no entry for address %s in trackedDials", res.Addr) + if res.Conn != nil { + res.Conn.Close() + } + continue + } if res.Conn != nil { // we got a connection, add it to the swarm @@ -204,32 +333,46 @@ loop: continue loop } - // dispatch to still pending requests + // request succeeded, respond to all pending requests for _, reqno := range ad.requests { - pr, ok := w.requests[reqno] + pr, ok := w.pendingRequests[reqno] if !ok { - // it has already dispatched a connection + // some other dial for this request succeeded before this one continue } - pr.req.resch <- dialResponse{conn: conn} - delete(w.requests, reqno) + delete(w.pendingRequests, reqno) } ad.conn = conn ad.requests = nil + if !w.connected { + w.connected = true + if w.s.metricsTracer != nil { + w.s.metricsTracer.DialRankingDelay(ad.dialRankingDelay) + } + } + continue loop } // it must be an error -- add backoff if applicable and dispatch - if res.Err != context.Canceled && !w.connected { + // ErrDialRefusedBlackHole shouldn't end up here, just a safety check + if res.Err != ErrDialRefusedBlackHole && res.Err != context.Canceled && !w.connected { // we only add backoff if there has not been a successful connection // for consistency with the old dialer behavior. w.s.backf.AddBackoff(w.peer, res.Addr) + } else if res.Err == ErrDialRefusedBlackHole { + log.Errorf("SWARM BUG: unexpected ErrDialRefusedBlackHole while dialing peer %s to addr %s", + w.peer, res.Addr) } w.dispatchError(ad, res.Err) + // Only schedule next dial on error. + // If we scheduleNextDial on success, we will end up making one dial more than + // required because the final successful dial will spawn one more dial + scheduleNextDial() } } } @@ -238,9 +381,9 @@ loop: func (w *dialWorker) dispatchError(ad *addrDial, err error) { ad.err = err for _, reqno := range ad.requests { - pr, ok := w.requests[reqno] + pr, ok := w.pendingRequests[reqno] if !ok { - // has already been dispatched + // some other dial for this request succeeded before this one continue } @@ -258,7 +401,7 @@ func (w *dialWorker) dispatchError(ad *addrDial, err error) { } else { pr.req.resch <- dialResponse{err: pr.err} } - delete(w.requests, reqno) + delete(w.pendingRequests, reqno) } } @@ -268,46 +411,82 @@ func (w *dialWorker) dispatchError(ad *addrDial, err error) { // this is necessary to support active listen scenarios, where a new dial comes in while // another dial is in progress, and needs to do a direct connection without inhibitions from // dial backoff. - // it is also necessary to preserve consisent behaviour with the old dialer -- TestDialBackoff - // regresses without this. if err == ErrDialBackoff { - delete(w.pending, string(ad.addr.Bytes())) + delete(w.trackedDials, string(ad.addr.Bytes())) } } -// ranks addresses in descending order of preference for dialing, with the following rules: -// NonRelay > Relay -// NonWS > WS -// Private > Public -// UDP > TCP -func (w *dialWorker) rankAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { - addrTier := func(a ma.Multiaddr) (tier int) { - if isRelayAddr(a) { - tier |= 0b1000 - } - if isExpensiveAddr(a) { - tier |= 0b0100 - } - if !manet.IsPrivateAddr(a) { - tier |= 0b0010 - } - if isFdConsumingAddr(a) { - tier |= 0b0001 +// rankAddrs ranks addresses for dialing. if it's a simConnect request we +// dial all addresses immediately without any delay +func (w *dialWorker) rankAddrs(addrs []ma.Multiaddr, isSimConnect bool) []network.AddrDelay { + if isSimConnect { + return NoDelayDialRanker(addrs) + } + return w.s.dialRanker(addrs) +} + +// dialQueue is a priority queue used to schedule dials +type dialQueue struct { + // q contains dials ordered by delay + q []network.AddrDelay +} + +// newDialQueue returns a new dialQueue +func newDialQueue() *dialQueue { + return &dialQueue{q: make([]network.AddrDelay, 0, 16)} +} + +// Add adds adelay to the queue. If another element exists in the queue with +// the same address, it replaces that element. +func (dq *dialQueue) Add(adelay network.AddrDelay) { + for i := 0; i < dq.len(); i++ { + if dq.q[i].Addr.Equal(adelay.Addr) { + if dq.q[i].Delay == adelay.Delay { + // existing element is the same. nothing to do + return + } + // remove the element + copy(dq.q[i:], dq.q[i+1:]) + dq.q = dq.q[:len(dq.q)-1] + break } + } - return tier + for i := 0; i < dq.len(); i++ { + if dq.q[i].Delay > adelay.Delay { + dq.q = append(dq.q, network.AddrDelay{}) // extend the slice + copy(dq.q[i+1:], dq.q[i:]) + dq.q[i] = adelay + return + } } + dq.q = append(dq.q, adelay) +} - tiers := make([][]ma.Multiaddr, 16) - for _, a := range addrs { - tier := addrTier(a) - tiers[tier] = append(tiers[tier], a) +// NextBatch returns all the elements in the queue with the highest priority +func (dq *dialQueue) NextBatch() []network.AddrDelay { + if dq.len() == 0 { + return nil } - result := make([]ma.Multiaddr, 0, len(addrs)) - for _, tier := range tiers { - result = append(result, tier...) + // i is the index of the second highest priority element + var i int + for i = 0; i < dq.len(); i++ { + if dq.q[i].Delay != dq.q[0].Delay { + break + } } + res := dq.q[:i] + dq.q = dq.q[i:] + return res +} + +// top returns the top element of the queue +func (dq *dialQueue) top() network.AddrDelay { + return dq.q[0] +} - return result +// len returns the number of elements in the queue +func (dq *dialQueue) len() int { + return len(dq.q) } diff --git a/p2p/net/swarm/dial_worker_test.go b/p2p/net/swarm/dial_worker_test.go index ebdaedb245..89130eeeb2 100644 --- a/p2p/net/swarm/dial_worker_test.go +++ b/p2p/net/swarm/dial_worker_test.go @@ -5,15 +5,22 @@ import ( "crypto/rand" "errors" "fmt" + "math" + mrand "math/rand" + "reflect" + "sort" "sync" "testing" + "testing/quick" "time" "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/sec" "github.com/libp2p/go-libp2p/core/sec/insecure" + "github.com/libp2p/go-libp2p/core/test" "github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" @@ -28,6 +35,18 @@ import ( "github.com/stretchr/testify/require" ) +type mockClock struct { + *test.MockClock +} + +func (m *mockClock) InstantTimer(when time.Time) InstantTimer { + return m.MockClock.InstantTimer(when) +} + +func newMockClock() *mockClock { + return &mockClock{test.NewMockClock()} +} + func newPeer(t *testing.T) (crypto.PrivKey, peer.ID) { priv, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(t, err) @@ -37,6 +56,19 @@ func newPeer(t *testing.T) (crypto.PrivKey, peer.ID) { } func makeSwarm(t *testing.T) *Swarm { + s := makeSwarmWithNoListenAddrs(t, WithDialTimeout(1*time.Second)) + if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")); err != nil { + t.Fatal(err) + } + + if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")); err != nil { + t.Fatal(err) + } + + return s +} + +func makeSwarmWithNoListenAddrs(t *testing.T, opts ...Option) *Swarm { priv, id := newPeer(t) ps, err := pstoremem.NewPeerstore() @@ -45,11 +77,10 @@ func makeSwarm(t *testing.T) *Swarm { ps.AddPrivKey(id, priv) t.Cleanup(func() { ps.Close() }) - s, err := NewSwarm(id, ps, eventbus.NewBus(), WithDialTimeout(time.Second)) + s, err := NewSwarm(id, ps, eventbus.NewBus(), opts...) require.NoError(t, err) upgrader := makeUpgrader(t, s) - var tcpOpts []tcp.Option tcpOpts = append(tcpOpts, tcp.DisableReuseport()) tcpTransport, err := tcp.NewTCPTransport(upgrader, nil, tcpOpts...) @@ -57,10 +88,6 @@ func makeSwarm(t *testing.T) *Swarm { if err := s.AddTransport(tcpTransport); err != nil { t.Fatal(err) } - if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")); err != nil { - t.Fatal(err) - } - reuse, err := quicreuse.NewConnManager([32]byte{}) if err != nil { t.Fatal(err) @@ -72,10 +99,6 @@ func makeSwarm(t *testing.T) *Swarm { if err := s.AddTransport(quicTransport); err != nil { t.Fatal(err) } - if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")); err != nil { - t.Fatal(err) - } - return s } @@ -89,6 +112,33 @@ func makeUpgrader(t *testing.T, n *Swarm) transport.Upgrader { return u } +// makeTCPListener listens on tcp address a. On accepting a connection it notifies recvCh. Sending a message to +// channel ch will close an accepted connection +func makeTCPListener(t *testing.T, a ma.Multiaddr, recvCh chan struct{}) (list manet.Listener, ch chan struct{}) { + t.Helper() + list, err := manet.Listen(a) + if err != nil { + t.Fatal(err) + } + ch = make(chan struct{}) + go func() { + for { + c, err := list.Accept() + if err != nil { + break + } + recvCh <- struct{}{} + <-ch + err = c.Close() + if err != nil { + t.Error(err) + } + + } + }() + return list, ch +} + func TestDialWorkerLoopBasic(t *testing.T) { s1 := makeSwarm(t) s2 := makeSwarm(t) @@ -100,7 +150,7 @@ func TestDialWorkerLoopBasic(t *testing.T) { reqch := make(chan dialRequest) resch := make(chan dialResponse) - worker := newDialWorker(s1, s2.LocalPeer(), reqch) + worker := newDialWorker(s1, s2.LocalPeer(), reqch, nil) go worker.loop() var conn *Conn @@ -145,7 +195,7 @@ func TestDialWorkerLoopConcurrent(t *testing.T) { s1.Peerstore().AddAddrs(s2.LocalPeer(), s2.ListenAddresses(), peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) - worker := newDialWorker(s1, s2.LocalPeer(), reqch) + worker := newDialWorker(s1, s2.LocalPeer(), reqch, nil) go worker.loop() const dials = 100 @@ -188,7 +238,7 @@ func TestDialWorkerLoopFailure(t *testing.T) { reqch := make(chan dialRequest) resch := make(chan dialResponse) - worker := newDialWorker(s1, p2, reqch) + worker := newDialWorker(s1, p2, reqch, nil) go worker.loop() reqch <- dialRequest{ctx: context.Background(), resch: resch} @@ -212,7 +262,7 @@ func TestDialWorkerLoopConcurrentFailure(t *testing.T) { s1.Peerstore().AddAddrs(p2, []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic")}, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) - worker := newDialWorker(s1, p2, reqch) + worker := newDialWorker(s1, p2, reqch, nil) go worker.loop() const dials = 100 @@ -260,7 +310,7 @@ func TestDialWorkerLoopConcurrentMix(t *testing.T) { s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic")}, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) - worker := newDialWorker(s1, s2.LocalPeer(), reqch) + worker := newDialWorker(s1, s2.LocalPeer(), reqch, nil) go worker.loop() const dials = 100 @@ -306,7 +356,7 @@ func TestDialWorkerLoopConcurrentFailureStress(t *testing.T) { s1.Peerstore().AddAddrs(p2, addrs, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) - worker := newDialWorker(s1, p2, reqch) + worker := newDialWorker(s1, p2, reqch, nil) go worker.loop() const dials = 100 @@ -344,6 +394,629 @@ func TestDialWorkerLoopConcurrentFailureStress(t *testing.T) { worker.wg.Wait() } +func TestDialQueueNextBatch(t *testing.T) { + addrs := make([]ma.Multiaddr, 0) + for i := 0; i < 10; i++ { + addrs = append(addrs, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i))) + } + testcase := []struct { + name string + input []network.AddrDelay + output [][]ma.Multiaddr + }{ + { + name: "next batch", + input: []network.AddrDelay{ + {Addr: addrs[0], Delay: 3}, + {Addr: addrs[1], Delay: 2}, + {Addr: addrs[2], Delay: 1}, + {Addr: addrs[3], Delay: 1}, + }, + output: [][]ma.Multiaddr{ + {addrs[2], addrs[3]}, + {addrs[1]}, + {addrs[0]}, + }, + }, + { + name: "priority queue property 2", + input: []network.AddrDelay{ + {Addr: addrs[0], Delay: 5}, + {Addr: addrs[1], Delay: 3}, + {Addr: addrs[2], Delay: 2}, + {Addr: addrs[3], Delay: 1}, + {Addr: addrs[4], Delay: 1}, + }, + + output: [][]ma.Multiaddr{ + {addrs[3], addrs[4]}, + {addrs[2]}, + {addrs[1]}, + {addrs[0]}, + }, + }, + { + name: "updates", + input: []network.AddrDelay{ + {Addr: addrs[0], Delay: 3}, // decreasing order + {Addr: addrs[1], Delay: 3}, + {Addr: addrs[2], Delay: 2}, + {Addr: addrs[3], Delay: 2}, + {Addr: addrs[4], Delay: 1}, + {Addr: addrs[0], Delay: 1}, // increasing order + {Addr: addrs[1], Delay: 1}, + {Addr: addrs[2], Delay: 2}, + {Addr: addrs[3], Delay: 2}, + {Addr: addrs[4], Delay: 3}, + }, + output: [][]ma.Multiaddr{ + {addrs[0], addrs[1]}, + {addrs[2], addrs[3]}, + {addrs[4]}, + {}, + }, + }, + { + name: "null input", + input: []network.AddrDelay{}, + output: [][]ma.Multiaddr{ + {}, + {}, + }, + }, + } + for _, tc := range testcase { + t.Run(tc.name, func(t *testing.T) { + q := newDialQueue() + for i := 0; i < len(tc.input); i++ { + q.Add(tc.input[i]) + } + for _, batch := range tc.output { + b := q.NextBatch() + if len(batch) != len(b) { + t.Errorf("expected %d elements got %d", len(batch), len(b)) + } + sort.Slice(b, func(i, j int) bool { return b[i].Addr.String() < b[j].Addr.String() }) + sort.Slice(batch, func(i, j int) bool { return batch[i].String() < batch[j].String() }) + for i := 0; i < len(b); i++ { + if !b[i].Addr.Equal(batch[i]) { + log.Errorf("expected %s got %s", batch[i], b[i].Addr) + } + } + } + if q.len() != 0 { + t.Errorf("expected queue to be empty at end. got: %d", q.len()) + } + }) + } +} + +// timedDial is a dial to a single address of the peer +type timedDial struct { + // addr is the address to dial + addr ma.Multiaddr + // delay is the delay after which this address should be dialed + delay time.Duration + // success indicates whether the dial should succeed + success bool + // failAfter is how long this dial should take to fail after it is dialed + failAfter time.Duration +} + +// schedulingTestCase is used to test dialWorker loop scheduler logic +// a ranker is made according to `input` which provides the addresses to +// dial worker loop with the specified delays +// checkDialWorkerLoopScheduling then verifies that the different dial calls are +// made at the right moments +type schedulingTestCase struct { + name string + input []timedDial + maxDuration time.Duration +} + +// schedulingTestCase generates a random test case +func (s schedulingTestCase) Generate(rand *mrand.Rand, size int) reflect.Value { + if size > 20 { + size = 20 + } + input := make([]timedDial, size) + delays := make(map[time.Duration]struct{}) + for i := 0; i < size; i++ { + input[i] = timedDial{ + addr: ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", i+10550)), + delay: time.Duration(mrand.Intn(100)) * 10 * time.Millisecond, // max 1 second + success: false, + failAfter: time.Duration(mrand.Intn(100)) * 10 * time.Millisecond, // max 1 second + } + delays[input[i].delay] = struct{}{} + } + successIdx := rand.Intn(size) + for { + // set a unique delay for success. This is required to test the property that + // no extra dials are made after success + d := time.Duration(rand.Intn(100)) * 10 * time.Millisecond + if _, ok := delays[d]; !ok { + input[successIdx].delay = d + input[successIdx].success = true + break + } + } + return reflect.ValueOf(schedulingTestCase{ + name: "", + input: input, + maxDuration: 10 * time.Second, // not tested here + }) +} + +// dialState is used to track the dials for testing dialWorker ranking logic +type dialState struct { + // ch is the chan used to trigger dial failure. + ch chan struct{} + // addr is the address of the dial + addr ma.Multiaddr + // delay is the delay after which this address should be dialed + delay time.Duration + // success indicates whether the dial should succeed + success bool + // failAfter is how long this dial should take to fail after it is dialed + failAfter time.Duration + // failAt is the instant at which this dial should fail if success is false + failAt time.Time +} + +// checkDialWorkerLoopScheduling verifies whether s1 dials s2 according to the +// schedule specified by the test case tc +func checkDialWorkerLoopScheduling(t *testing.T, s1, s2 *Swarm, tc schedulingTestCase) error { + t.Helper() + // failDials is used to track dials which should fail in the future + // at appropriate moment a message is sent to dialState.ch to trigger + // failure + failDials := make(map[ma.Multiaddr]dialState) + // recvCh is used to receive dial notifications for dials that will fail + recvCh := make(chan struct{}, 100) + // allDials tracks all pending dials + allDials := make(map[ma.Multiaddr]dialState) + // addrs are the peer addresses the swarm will use for dialing + addrs := make([]ma.Multiaddr, 0) + // create pending dials + // we add success cases as a listen address on swarm + // failed cases are created using makeTCPListener + for _, inp := range tc.input { + var failCh chan struct{} + if inp.success { + // add the address as a listen address if this dial should succeed + err := s2.AddListenAddr(inp.addr) + if err != nil { + return fmt.Errorf("failed to listen on addr: %s: err: %w", inp.addr, err) + } + } else { + // make a listener which will fail on sending a message to ch + l, ch := makeTCPListener(t, inp.addr, recvCh) + failCh = ch + f := func() { + err := l.Close() + if err != nil { + t.Error(err) + } + } + defer f() + } + addrs = append(addrs, inp.addr) + // add to pending dials + allDials[inp.addr] = dialState{ + ch: failCh, + addr: inp.addr, + delay: inp.delay, + success: inp.success, + failAfter: inp.failAfter, + } + } + // setup the peers addresses + s1.Peerstore().AddAddrs(s2.LocalPeer(), addrs, peerstore.PermanentAddrTTL) + + // create worker + reqch := make(chan dialRequest) + resch := make(chan dialResponse) + cl := newMockClock() + st := cl.Now() + worker1 := newDialWorker(s1, s2.LocalPeer(), reqch, cl) + go worker1.loop() + defer worker1.wg.Wait() + defer close(reqch) + + // trigger the request + reqch <- dialRequest{ctx: context.Background(), resch: resch} + + connected := false + + // Advance the clock by 10 ms every iteration + // At every iteration: + // Check if any dial should fail. if it should, trigger the failure by sending a message on the + // listener failCh + // If there are no dials in flight check the most urgent dials have been triggered + // If there are dials in flight check that the relevant dials have been triggered + // Before next iteration ensure that no unexpected dials are received +loop: + for { + // fail any dials that should fail at this instant + for a, p := range failDials { + if p.failAt.Before(cl.Now()) || p.failAt == cl.Now() { + p.ch <- struct{}{} + delete(failDials, a) + } + } + // if there are no pending dials, next dial should have been triggered + trigger := len(failDials) == 0 + + // mi is the minimum delay of pending dials + // if trigger is true, all dials with miDelay should have been triggered + mi := time.Duration(math.MaxInt64) + for _, ds := range allDials { + if ds.delay < mi { + mi = ds.delay + } + } + for a, ds := range allDials { + if (trigger && mi == ds.delay) || + cl.Now().After(st.Add(ds.delay)) || + cl.Now() == st.Add(ds.delay) { + if ds.success { + // check for success and exit + select { + case r := <-resch: + if r.conn == nil { + return errors.New("expected connection to succeed") + } + // High timeout here is okay. We will exit whenever the other branch + // is triggered + case <-time.After(10 * time.Second): + return errors.New("expected to receive a response") + } + connected = true + break loop + } else { + // ensure that a failing dial attempt happened but didn't succeed + select { + case <-recvCh: + case <-resch: + return errors.New("didn't expect a response") + // High timeout here is okay. We will exit whenever the other branch + // is triggered + case <-time.After(10 * time.Second): + return errors.New("didn't receive a dial attempt notification") + } + failDials[a] = dialState{ + ch: ds.ch, + failAt: cl.Now().Add(ds.failAfter), + addr: a, + delay: ds.delay, + } + } + delete(allDials, a) + } + } + // check for unexpected dials + select { + case <-recvCh: + return errors.New("no dial should have succeeded at this instant") + default: + } + + // advance the clock + cl.AdvanceBy(10 * time.Millisecond) + // nothing more to do. exit + if len(failDials) == 0 && len(allDials) == 0 { + break + } + } + + if connected { + // ensure we don't receive any extra connections + select { + case <-recvCh: + return errors.New("didn't expect a dial attempt") + case <-time.After(100 * time.Millisecond): + } + } else { + // ensure that we do receive the final error response + select { + case r := <-resch: + require.Error(t, r.err) + case <-time.After(100 * time.Millisecond): + return errors.New("expected to receive response") + } + } + // check if this test didn't take too much time + if cl.Now().Sub(st) > tc.maxDuration { + return fmt.Errorf("expected test to finish early: expected %d, took: %d", tc.maxDuration, cl.Now().Sub(st)) + } + return nil +} + +// makeRanker takes a slice of timedDial objects and returns a DialRanker +// which will trigger dials to addresses at the specified delays in the timedDials +func makeRanker(tc []timedDial) network.DialRanker { + return func(addrs []ma.Multiaddr) []network.AddrDelay { + res := make([]network.AddrDelay, len(tc)) + for i := 0; i < len(tc); i++ { + res[i] = network.AddrDelay{Addr: tc[i].addr, Delay: tc[i].delay} + } + return res + } +} + +// TestCheckDialWorkerLoopScheduling will check the checker +func TestCheckDialWorkerLoopScheduling(t *testing.T) { + addrs := make([]ma.Multiaddr, 0) + for i := 0; i < 10; i++ { + for { + p := 20000 + i + addrs = append(addrs, ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", p))) + break + } + } + + tc := schedulingTestCase{ + input: []timedDial{ + { + addr: addrs[1], + delay: 0, + success: true, + }, + { + addr: addrs[0], + delay: 100 * time.Millisecond, + success: false, + failAfter: 50 * time.Millisecond, + }, + }, + maxDuration: 20 * time.Millisecond, + } + s1 := makeSwarmWithNoListenAddrs(t) + s2 := makeSwarmWithNoListenAddrs(t) + // valid ranking logic, so it shouldn't error + s1.dialRanker = makeRanker(tc.input) + err := checkDialWorkerLoopScheduling(t, s1, s2, tc) + require.NoError(t, err) + // close swarms to remove address binding + s1.Close() + s2.Close() + + s3 := makeSwarmWithNoListenAddrs(t) + defer s3.Close() + s4 := makeSwarmWithNoListenAddrs(t) + defer s4.Close() + // invalid ranking logic to trigger an error + s3.dialRanker = NoDelayDialRanker + err = checkDialWorkerLoopScheduling(t, s3, s4, tc) + require.Error(t, err) +} + +func TestDialWorkerLoopRanking(t *testing.T) { + addrs := make([]ma.Multiaddr, 0) + for i := 0; i < 10; i++ { + for { + p := 20000 + i + addrs = append(addrs, ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", p))) + break + } + } + + testcases := []schedulingTestCase{ + { + name: "first success", + input: []timedDial{ + { + addr: addrs[1], + delay: 0, + success: true, + }, + { + addr: addrs[0], + delay: 100 * time.Millisecond, + success: false, + failAfter: 50 * time.Millisecond, + }, + }, + maxDuration: 20 * time.Millisecond, + }, + { + name: "delayed dials", + input: []timedDial{ + { + addr: addrs[0], + delay: 0, + success: false, + failAfter: 200 * time.Millisecond, + }, + { + addr: addrs[1], + delay: 100 * time.Millisecond, + success: false, + failAfter: 100 * time.Millisecond, + }, + { + addr: addrs[2], + delay: 300 * time.Millisecond, + success: false, + failAfter: 100 * time.Millisecond, + }, + { + addr: addrs[3], + delay: 2 * time.Second, + success: true, + }, + { + addr: addrs[4], + delay: 2*time.Second + 1*time.Millisecond, + success: false, // this call will never happened + failAfter: 100 * time.Millisecond, + }, + }, + maxDuration: 310 * time.Millisecond, + }, + { + name: "failed dials", + input: []timedDial{ + { + addr: addrs[0], + delay: 0, + success: false, + failAfter: 105 * time.Millisecond, + }, + { + addr: addrs[1], + delay: 100 * time.Millisecond, + success: false, + failAfter: 20 * time.Millisecond, + }, + }, + maxDuration: 200 * time.Millisecond, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + s1 := makeSwarmWithNoListenAddrs(t) + defer s1.Close() + s2 := makeSwarmWithNoListenAddrs(t) + defer s2.Close() + // setup the ranker to trigger dials according to the test case + s1.dialRanker = makeRanker(tc.input) + err := checkDialWorkerLoopScheduling(t, s1, s2, tc) + if err != nil { + t.Error(err) + } + }) + } +} + +func TestDialWorkerLoopSchedulingProperty(t *testing.T) { + f := func(tc schedulingTestCase) bool { + s1 := makeSwarmWithNoListenAddrs(t) + defer s1.Close() + // ignore limiter delays just check scheduling + s1.limiter.perPeerLimit = 10000 + s2 := makeSwarmWithNoListenAddrs(t) + defer s2.Close() + // setup the ranker to trigger dials according to the test case + s1.dialRanker = makeRanker(tc.input) + err := checkDialWorkerLoopScheduling(t, s1, s2, tc) + if err != nil { + log.Error(err) + } + return err == nil + } + + if err := quick.Check(f, &quick.Config{MaxCount: 50}); err != nil { + t.Error(err) + } +} + +func TestDialWorkerLoopQuicOverTCP(t *testing.T) { + tc := schedulingTestCase{ + input: []timedDial{ + { + addr: ma.StringCast("/ip4/127.0.0.1/udp/20000/quic"), + delay: 0, + success: true, + }, + { + addr: ma.StringCast("/ip4/127.0.0.1/tcp/20000"), + delay: 30 * time.Millisecond, + success: true, + }, + }, + maxDuration: 20 * time.Millisecond, + } + s1 := makeSwarmWithNoListenAddrs(t) + defer s1.Close() + + s2 := makeSwarmWithNoListenAddrs(t) + defer s2.Close() + + // we use the default ranker here + + err := checkDialWorkerLoopScheduling(t, s1, s2, tc) + require.NoError(t, err) +} + +func TestDialWorkerLoopHolePunching(t *testing.T) { + s1 := makeSwarmWithNoListenAddrs(t) + defer s1.Close() + + s2 := makeSwarmWithNoListenAddrs(t) + defer s2.Close() + + // t1 will accept and keep the other end waiting + t1 := ma.StringCast("/ip4/127.0.0.1/tcp/10000") + recvCh := make(chan struct{}) + list, ch := makeTCPListener(t, t1, recvCh) // ignore ch because we want to hang forever + defer list.Close() + defer func() { ch <- struct{}{} }() // close listener + + // t2 will succeed + t2 := ma.StringCast("/ip4/127.0.0.1/tcp/10001") + + err := s2.AddListenAddr(t2) + if err != nil { + t.Error(err) + } + + s1.dialRanker = func(addrs []ma.Multiaddr) (res []network.AddrDelay) { + res = make([]network.AddrDelay, len(addrs)) + for i := 0; i < len(addrs); i++ { + delay := 10 * time.Second + if addrs[i].Equal(t1) { + //fire t1 immediately + delay = 0 + } else if addrs[i].Equal(t2) { + // delay t2 by 100ms + // without holepunch this call will not happen + delay = 100 * time.Millisecond + } + res[i] = network.AddrDelay{Addr: addrs[i], Delay: delay} + } + return + } + s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{t1, t2}, peerstore.PermanentAddrTTL) + + reqch := make(chan dialRequest) + resch := make(chan dialResponse, 2) + + cl := newMockClock() + worker := newDialWorker(s1, s2.LocalPeer(), reqch, cl) + go worker.loop() + defer worker.wg.Wait() + defer close(reqch) + + reqch <- dialRequest{ctx: context.Background(), resch: resch} + <-recvCh // received connection on t1 + + select { + case <-resch: + t.Errorf("didn't expect connection to succeed") + case <-time.After(100 * time.Millisecond): + } + + hpCtx := network.WithSimultaneousConnect(context.Background(), true, "testing") + // with holepunch request, t2 will be dialed immediately + reqch <- dialRequest{ctx: hpCtx, resch: resch} + select { + case r := <-resch: + require.NoError(t, r.err) + case <-time.After(5 * time.Second): + t.Errorf("expected conn to succeed") + } + + select { + case r := <-resch: + require.NoError(t, r.err) + case <-time.After(5 * time.Second): + t.Errorf("expected conn to succeed") + } +} + func TestDialWorkerLoopAddrDedup(t *testing.T) { s1 := makeSwarm(t) s2 := makeSwarm(t) @@ -384,7 +1057,7 @@ func TestDialWorkerLoopAddrDedup(t *testing.T) { reqch := make(chan dialRequest) resch := make(chan dialResponse, 2) - worker := newDialWorker(s1, s2.LocalPeer(), reqch) + worker := newDialWorker(s1, s2.LocalPeer(), reqch, nil) go worker.loop() defer worker.wg.Wait() defer close(reqch) diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go index cd19e726ed..5155cd2228 100644 --- a/p2p/net/swarm/swarm.go +++ b/p2p/net/swarm/swarm.go @@ -100,6 +100,37 @@ func WithResourceManager(m network.ResourceManager) Option { } } +// WithDialRanker configures swarm to use d as the DialRanker +func WithDialRanker(d network.DialRanker) Option { + return func(s *Swarm) error { + if d == nil { + return errors.New("swarm: dial ranker cannot be nil") + } + s.dialRanker = d + return nil + } +} + +// WithUDPBlackHoleConfig configures swarm to use c as the config for UDP black hole detection +// n is the size of the sliding window used to evaluate black hole state +// min is the minimum number of successes out of n required to not block requests +func WithUDPBlackHoleConfig(enabled bool, n, min int) Option { + return func(s *Swarm) error { + s.udpBlackHoleConfig = blackHoleConfig{Enabled: enabled, N: n, MinSuccesses: min} + return nil + } +} + +// WithIPv6BlackHoleConfig configures swarm to use c as the config for IPv6 black hole detection +// n is the size of the sliding window used to evaluate black hole state +// min is the minimum number of successes out of n required to not block requests +func WithIPv6BlackHoleConfig(enabled bool, n, min int) Option { + return func(s *Swarm) error { + s.ipv6BlackHoleConfig = blackHoleConfig{Enabled: enabled, N: n, MinSuccesses: min} + return nil + } +} + // Swarm is a connection muxer, allowing connections to other peers to // be opened and closed, while still using the same Chan for all // communication. The Chan sends/receives Messages, which note the @@ -163,6 +194,12 @@ type Swarm struct { bwc metrics.Reporter metricsTracer MetricsTracer + + dialRanker network.DialRanker + + udpBlackHoleConfig blackHoleConfig + ipv6BlackHoleConfig blackHoleConfig + bhd *blackHoleDetector } // NewSwarm constructs a Swarm. @@ -181,6 +218,13 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts dialTimeout: defaultDialTimeout, dialTimeoutLocal: defaultDialTimeoutLocal, maResolver: madns.DefaultResolver, + dialRanker: DefaultDialRanker, + + // A black hole is a binary property. On a network if UDP dials are blocked or there is + // no IPv6 connectivity, all dials will fail. So a low success rate of 5 out 100 dials + // is good enough. + udpBlackHoleConfig: blackHoleConfig{Enabled: true, N: 100, MinSuccesses: 5}, + ipv6BlackHoleConfig: blackHoleConfig{Enabled: true, N: 100, MinSuccesses: 5}, } s.conns.m = make(map[peer.ID][]*Conn) @@ -198,8 +242,12 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts } s.dsync = newDialSync(s.dialWorkerLoop) + s.limiter = newDialLimiter(s.dialAddr) s.backf.init(s.ctx) + + s.bhd = newBlackHoleDetector(s.udpBlackHoleConfig, s.ipv6BlackHoleConfig, s.metricsTracer) + return s, nil } @@ -229,7 +277,7 @@ func (s *Swarm) close() { for l := range listeners { go func(l transport.Listener) { - if err := l.Close(); err != nil { + if err := l.Close(); err != nil && err != transport.ErrListenerClosed { log.Errorf("error when shutting down listener: %s", err) } }(l) @@ -329,12 +377,7 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, } c.streams.m = make(map[*Stream]struct{}) - if len(s.conns.m[p]) == 0 { // first connection - s.emitter.Emit(event.EvtPeerConnectednessChanged{ - Peer: p, - Connectedness: network.Connected, - }) - } + isFirstConnection := len(s.conns.m[p]) == 0 s.conns.m[p] = append(s.conns.m[p], c) // Add two swarm refs: @@ -347,6 +390,15 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, c.notifyLk.Lock() s.conns.Unlock() + // Emit event after releasing `s.conns` lock so that a consumer can still + // use swarm methods that need the `s.conns` lock. + if isFirstConnection { + s.emitter.Emit(event.EvtPeerConnectednessChanged{ + Peer: p, + Connectedness: network.Connected, + }) + } + s.notifyAll(func(f network.Notifiee) { f.Connected(s, c) }) @@ -626,25 +678,32 @@ func (s *Swarm) removeConn(c *Conn) { p := c.RemotePeer() s.conns.Lock() - defer s.conns.Unlock() cs := s.conns.m[p] + + if len(cs) == 1 { + delete(s.conns.m, p) + s.conns.Unlock() + + // Emit event after releasing `s.conns` lock so that a consumer can still + // use swarm methods that need the `s.conns` lock. + s.emitter.Emit(event.EvtPeerConnectednessChanged{ + Peer: p, + Connectedness: network.NotConnected, + }) + return + } + + defer s.conns.Unlock() + for i, ci := range cs { if ci == c { - if len(cs) == 1 { - delete(s.conns.m, p) - s.emitter.Emit(event.EvtPeerConnectednessChanged{ - Peer: p, - Connectedness: network.NotConnected, - }) - } else { - // NOTE: We're intentionally preserving order. - // This way, connections to a peer are always - // sorted oldest to newest. - copy(cs[i:], cs[i+1:]) - cs[len(cs)-1] = nil - s.conns.m[p] = cs[:len(cs)-1] - } + // NOTE: We're intentionally preserving order. + // This way, connections to a peer are always + // sorted oldest to newest. + copy(cs[i:], cs[i+1:]) + cs[len(cs)-1] = nil + s.conns.m[p] = cs[:len(cs)-1] break } } @@ -684,3 +743,12 @@ func (c connWithMetrics) Close() error { c.metricsTracer.ClosedConnection(c.dir, time.Since(c.opened), c.ConnState(), c.LocalMultiaddr()) return c.CapableConn.Close() } + +func (c connWithMetrics) Stat() network.ConnStats { + if cs, ok := c.CapableConn.(network.ConnStat); ok { + return cs.Stat() + } + return network.ConnStats{} +} + +var _ network.ConnStat = connWithMetrics{} diff --git a/p2p/net/swarm/swarm_conn.go b/p2p/net/swarm/swarm_conn.go index 0e79da1b62..e770381a2e 100644 --- a/p2p/net/swarm/swarm_conn.go +++ b/p2p/net/swarm/swarm_conn.go @@ -130,6 +130,7 @@ func (c *Conn) start() { // We only get an error here when the swarm is closed or closing. if err != nil { + scope.Done() return } diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index 5423a199b7..f2df93af2f 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "net/netip" + "strconv" "sync" "time" @@ -15,7 +17,6 @@ import ( ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" manet "github.com/multiformats/go-multiaddr/net" - "github.com/quic-go/quic-go" ) // The maximum number of address resolution steps we'll perform for a single @@ -38,6 +39,9 @@ var ( // been dialed too frequently ErrDialBackoff = errors.New("dial backoff") + // ErrDialRefusedBlackHole is returned when we are in a black holed environment + ErrDialRefusedBlackHole = errors.New("dial refused because of black hole") + // ErrDialToSelf is returned if we attempt to dial our own peer ErrDialToSelf = errors.New("dial to self attempted") @@ -74,33 +78,12 @@ const ConcurrentFdDials = 160 // per peer var DefaultPerPeerRateLimit = 8 -// dialbackoff is a struct used to avoid over-dialing the same, dead peers. -// Whenever we totally time out on a peer (all three attempts), we add them -// to dialbackoff. Then, whenevers goroutines would _wait_ (dialsync), they -// check dialbackoff. If it's there, they don't wait and exit promptly with -// an error. (the single goroutine that is actually dialing continues to -// dial). If a dial is successful, the peer is removed from backoff. -// Example: -// -// for { -// if ok, wait := dialsync.Lock(p); !ok { -// if backoff.Backoff(p) { -// return errDialFailed -// } -// <-wait -// continue -// } -// defer dialsync.Unlock(p) -// c, err := actuallyDial(p) -// if err != nil { -// dialbackoff.AddBackoff(p) -// continue -// } -// dialbackoff.Clear(p) -// } -// - -// DialBackoff is a type for tracking peer dial backoffs. +// DialBackoff is a type for tracking peer dial backoffs. Dialbackoff is used to +// avoid over-dialing the same, dead peers. Whenever we totally time out on all +// addresses of a peer, we add the addresses to DialBackoff. Then, whenever we +// attempt to dial the peer again, we check each address for backoff. If it's on +// backoff, we don't dial the address and exit promptly. If a dial is +// successful, the peer and all its addresses are removed from backoff. // // * It's safe to use its zero value. // * It's thread-safe. @@ -138,8 +121,8 @@ func (db *DialBackoff) background(ctx context.Context) { // Backoff returns whether the client should backoff from dialing // peer p at address addr func (db *DialBackoff) Backoff(p peer.ID, addr ma.Multiaddr) (backoff bool) { - db.lock.Lock() - defer db.lock.Unlock() + db.lock.RLock() + defer db.lock.RUnlock() ap, found := db.entries[p][string(addr.Bytes())] return found && time.Now().Before(ap.until) @@ -154,9 +137,7 @@ var BackoffCoef = time.Second // BackoffMax is the maximum backoff time (default: 5m). var BackoffMax = time.Minute * 5 -// AddBackoff lets other nodes know that we've entered backoff with -// peer p, so dialers should not wait unnecessarily. We still will -// attempt to dial with one goroutine, in case we get through. +// AddBackoff adds peer's address to backoff. // // Backoff is not exponential, it's quadratic and computed according to the // following formula: @@ -295,7 +276,7 @@ func (s *Swarm) dialPeer(ctx context.Context, p peer.ID) (*Conn, error) { // dialWorkerLoop synchronizes and executes concurrent dials to a single peer func (s *Swarm) dialWorkerLoop(p peer.ID, reqch <-chan dialRequest) { - w := newDialWorker(s, p, reqch) + w := newDialWorker(s, p, reqch, nil) w.loop() } @@ -334,6 +315,7 @@ func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) ([]ma.Multiaddr, er if forceDirect, _ := network.GetForceDirectDial(ctx); forceDirect { goodAddrs = ma.FilterAddrs(goodAddrs, s.nonProxyAddr) } + goodAddrs = ma.Unique(goodAddrs) if len(goodAddrs) == 0 { return nil, ErrNoGoodAddresses @@ -433,30 +415,43 @@ func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool { // filterKnownUndialables takes a list of multiaddrs, and removes those // that we definitely don't want to dial: addresses configured to be blocked, // IPv6 link-local addresses, addresses without a dial-capable transport, -// and addresses that we know to be our own. -// This is an optimization to avoid wasting time on dials that we know are going to fail. +// addresses that we know to be our own, and addresses with a better tranport +// available. This is an optimization to avoid wasting time on dials that we +// know are going to fail or for which we have a better alternative. func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) []ma.Multiaddr { lisAddrs, _ := s.InterfaceListenAddresses() var ourAddrs []ma.Multiaddr for _, addr := range lisAddrs { - protos := addr.Protocols() // we're only sure about filtering out /ip4 and /ip6 addresses, so far - if protos[0].Code == ma.P_IP4 || protos[0].Code == ma.P_IP6 { - ourAddrs = append(ourAddrs, addr) - } + ma.ForEach(addr, func(c ma.Component) bool { + if c.Protocol().Code == ma.P_IP4 || c.Protocol().Code == ma.P_IP6 { + ourAddrs = append(ourAddrs, addr) + } + return false + }) } - return maybeRemoveWebTransportAddrs( - maybeRemoveQUICDraft29( - ma.FilterAddrs(addrs, - func(addr ma.Multiaddr) bool { return !ma.Contains(ourAddrs, addr) }, - s.canDial, - // TODO: Consider allowing link-local addresses - func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) }, - func(addr ma.Multiaddr) bool { - return s.gater == nil || s.gater.InterceptAddrDial(p, addr) - }, - ))) + // The order of these two filters is important. If we can only dial /webtransport, + // we don't want to filter /webtransport addresses out because the peer had a /quic-v1 + // address + + // filter addresses we cannot dial + addrs = ma.FilterAddrs(addrs, s.canDial) + + // filter low priority addresses among the addresses we can dial + addrs = filterLowPriorityAddresses(addrs) + + // remove black holed addrs + addrs = s.bhd.FilterAddrs(addrs) + + return ma.FilterAddrs(addrs, + func(addr ma.Multiaddr) bool { return !ma.Contains(ourAddrs, addr) }, + // TODO: Consider allowing link-local addresses + func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) }, + func(addr ma.Multiaddr) bool { + return s.gater == nil || s.gater.InterceptAddrDial(p, addr) + }, + ) } // limitedDial will start a dial to the given peer when @@ -496,6 +491,12 @@ func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (tra start := time.Now() connC, err := tpt.Dial(ctx, addr, p) + + // We're recording any error as a failure here. + // Notably, this also applies to cancelations (i.e. if another dial attempt was faster). + // This is ok since the black hole detector uses a very low threshold (5%). + s.bhd.RecordResult(addr, err == nil) + if err != nil { if s.metricsTracer != nil { s.metricsTracer.FailedDialing(addr, err) @@ -542,110 +543,84 @@ func isFdConsumingAddr(addr ma.Multiaddr) bool { return err1 == nil || err2 == nil } -func isExpensiveAddr(addr ma.Multiaddr) bool { - _, wsErr := addr.ValueForProtocol(ma.P_WS) - _, wssErr := addr.ValueForProtocol(ma.P_WSS) - _, wtErr := addr.ValueForProtocol(ma.P_WEBTRANSPORT) - return wsErr == nil || wssErr == nil || wtErr == nil -} - func isRelayAddr(addr ma.Multiaddr) bool { _, err := addr.ValueForProtocol(ma.P_CIRCUIT) return err == nil } -func isWebTransport(addr ma.Multiaddr) bool { - _, err := addr.ValueForProtocol(ma.P_WEBTRANSPORT) - return err == nil -} - -func quicVersion(addr ma.Multiaddr) (quic.VersionNumber, bool) { - found := false - foundWebTransport := false - var version quic.VersionNumber - ma.ForEach(addr, func(c ma.Component) bool { - switch c.Protocol().Code { - case ma.P_QUIC: - version = quic.VersionDraft29 - found = true - return true - case ma.P_QUIC_V1: - version = quic.Version1 - found = true - return true - case ma.P_WEBTRANSPORT: - version = quic.Version1 - foundWebTransport = true - return false - default: - return true +// filterLowPriorityAddresses removes addresses inplace for which we have a better alternative +// 1. If a /quic-v1 address is present, filter out /quic and /webtransport address on the same 2-tuple: +// QUIC v1 is preferred over the deprecated QUIC draft-29, and given the choice, we prefer using +// raw QUIC over using WebTransport. +// 2. If a /tcp address is present, filter out /ws or /wss addresses on the same 2-tuple: +// We prefer using raw TCP over using WebSocket. +func filterLowPriorityAddresses(addrs []ma.Multiaddr) []ma.Multiaddr { + // make a map of QUIC v1 and TCP AddrPorts. + quicV1Addr := make(map[netip.AddrPort]struct{}) + tcpAddr := make(map[netip.AddrPort]struct{}) + for _, a := range addrs { + switch { + case isProtocolAddr(a, ma.P_WEBTRANSPORT): + case isProtocolAddr(a, ma.P_QUIC_V1): + ap, err := addrPort(a, ma.P_UDP) + if err != nil { + continue + } + quicV1Addr[ap] = struct{}{} + case isProtocolAddr(a, ma.P_WS) || isProtocolAddr(a, ma.P_WSS): + case isProtocolAddr(a, ma.P_TCP): + ap, err := addrPort(a, ma.P_TCP) + if err != nil { + continue + } + tcpAddr[ap] = struct{}{} } - }) - if foundWebTransport { - return 0, false } - return version, found -} -// If we have QUIC addresses, we don't want to dial WebTransport addresses. -// It's better to have a native QUIC connection. -// Note that this is a hack. The correct solution would be a proper -// Happy-Eyeballs-style dialing. -func maybeRemoveWebTransportAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { - var hasQuic, hasWebTransport bool - for _, addr := range addrs { - if _, isQuic := quicVersion(addr); isQuic { - hasQuic = true - } - if isWebTransport(addr) { - hasWebTransport = true - } - } - if !hasWebTransport || !hasQuic { - return addrs - } - var c int - for _, addr := range addrs { - if isWebTransport(addr) { - continue + i := 0 + for _, a := range addrs { + switch { + case isProtocolAddr(a, ma.P_WEBTRANSPORT) || isProtocolAddr(a, ma.P_QUIC): + ap, err := addrPort(a, ma.P_UDP) + if err != nil { + break + } + if _, ok := quicV1Addr[ap]; ok { + continue + } + case isProtocolAddr(a, ma.P_WS) || isProtocolAddr(a, ma.P_WSS): + ap, err := addrPort(a, ma.P_TCP) + if err != nil { + break + } + if _, ok := tcpAddr[ap]; ok { + continue + } } - addrs[c] = addr - c++ + addrs[i] = a + i++ } - return addrs[:c] + return addrs[:i] } -// If we have QUIC V1 addresses, we don't want to dial QUIC draft29 addresses. -// This is a similar hack to the above. If we add one more hack like this, let's -// define a `Filterer` interface like the `Resolver` interface that transports -// can optionally implement if they want to filter the multiaddrs. -// -// This mutates the input -func maybeRemoveQUICDraft29(addrs []ma.Multiaddr) []ma.Multiaddr { - var hasQuicV1, hasQuicDraft29 bool - for _, addr := range addrs { - v, isQuic := quicVersion(addr) - if !isQuic { - continue - } - - if v == quic.Version1 { - hasQuicV1 = true - } - if v == quic.VersionDraft29 { - hasQuicDraft29 = true - } +// addrPort returns the ip and port for a. p should be either ma.P_TCP or ma.P_UDP. +// a must be an (ip, TCP) or (ip, udp) address. +func addrPort(a ma.Multiaddr, p int) (netip.AddrPort, error) { + ip, err := manet.ToIP(a) + if err != nil { + return netip.AddrPort{}, err } - if !hasQuicDraft29 || !hasQuicV1 { - return addrs + port, err := a.ValueForProtocol(p) + if err != nil { + return netip.AddrPort{}, err } - var c int - for _, addr := range addrs { - if v, isQuic := quicVersion(addr); isQuic && v == quic.VersionDraft29 { - continue - } - addrs[c] = addr - c++ + pi, err := strconv.Atoi(port) + if err != nil { + return netip.AddrPort{}, err + } + addr, ok := netip.AddrFromSlice(ip) + if !ok { + return netip.AddrPort{}, fmt.Errorf("failed to parse IP %s", ip) } - return addrs[:c] + return netip.AddrPortFrom(addr, uint16(pi)), nil } diff --git a/p2p/net/swarm/swarm_dial_test.go b/p2p/net/swarm/swarm_dial_test.go index 566a2307f4..2f6b3f8c4d 100644 --- a/p2p/net/swarm/swarm_dial_test.go +++ b/p2p/net/swarm/swarm_dial_test.go @@ -1,9 +1,11 @@ package swarm import ( + "bytes" "context" "crypto/rand" "net" + "sort" "testing" "time" @@ -14,8 +16,12 @@ import ( "github.com/libp2p/go-libp2p/core/test" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" "github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/libp2p/go-libp2p/p2p/transport/websocket" + libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" + "github.com/quic-go/quic-go" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" @@ -65,6 +71,51 @@ func TestAddrsForDial(t *testing.T) { require.NotZero(t, len(mas)) } +func TestDedupAddrsForDial(t *testing.T) { + mockResolver := madns.MockResolver{IP: make(map[string][]net.IPAddr)} + ipaddr, err := net.ResolveIPAddr("ip4", "1.2.3.4") + if err != nil { + t.Fatal(err) + } + mockResolver.IP["example.com"] = []net.IPAddr{*ipaddr} + + resolver, err := madns.NewResolver(madns.WithDomainResolver("example.com", &mockResolver)) + if err != nil { + t.Fatal(err) + } + + priv, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + id, err := peer.IDFromPrivateKey(priv) + require.NoError(t, err) + + ps, err := pstoremem.NewPeerstore() + require.NoError(t, err) + ps.AddPubKey(id, priv.GetPublic()) + ps.AddPrivKey(id, priv) + t.Cleanup(func() { ps.Close() }) + + s, err := NewSwarm(id, ps, eventbus.NewBus(), WithMultiaddrResolver(resolver)) + require.NoError(t, err) + defer s.Close() + + tpt, err := tcp.NewTCPTransport(nil, &network.NullResourceManager{}) + require.NoError(t, err) + err = s.AddTransport(tpt) + require.NoError(t, err) + + otherPeer := test.RandPeerIDFatal(t) + + ps.AddAddr(otherPeer, ma.StringCast("/dns4/example.com/tcp/1234"), time.Hour) + ps.AddAddr(otherPeer, ma.StringCast("/ip4/1.2.3.4/tcp/1234"), time.Hour) + + ctx := context.Background() + mas, err := s.addrsForDial(ctx, otherPeer) + require.NoError(t, err) + + require.Equal(t, 1, len(mas)) +} + func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm { priv, _, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(t, err) @@ -87,6 +138,23 @@ func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm { err = s.AddTransport(tpt) require.NoError(t, err) + connmgr, err := quicreuse.NewConnManager(quic.StatelessResetKey{}) + require.NoError(t, err) + quicTpt, err := libp2pquic.NewTransport(priv, connmgr, nil, nil, &network.NullResourceManager{}) + require.NoError(t, err) + err = s.AddTransport(quicTpt) + require.NoError(t, err) + + wtTpt, err := libp2pwebtransport.New(priv, nil, connmgr, nil, &network.NullResourceManager{}) + require.NoError(t, err) + err = s.AddTransport(wtTpt) + require.NoError(t, err) + + wsTpt, err := websocket.New(nil, &network.NullResourceManager{}) + require.NoError(t, err) + err = s.AddTransport(wsTpt) + require.NoError(t, err) + return s } @@ -194,26 +262,114 @@ func TestAddrResolutionRecursive(t *testing.T) { require.Contains(t, addrs2, addr1) } -func TestRemoveWebTransportAddrs(t *testing.T) { - tcpAddr := ma.StringCast("/ip4/9.5.6.4/tcp/1234") - quicAddr := ma.StringCast("/ip4/1.2.3.4/udp/443/quic") - webtransportAddr := ma.StringCast("/ip4/1.2.3.4/udp/443/quic-v1/webtransport") +func TestAddrsForDialFiltering(t *testing.T) { + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") + + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") + wt2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1/webtransport/") + + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + + t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1") + ws1 := ma.StringCast("/ip4/1.2.3.4/tcp/1/ws") + + resolver, err := madns.NewResolver(madns.WithDefaultResolver(&madns.MockResolver{})) + require.NoError(t, err) + s := newTestSwarmWithResolver(t, resolver) + ourAddrs := s.ListenAddresses() + + testCases := []struct { + name string + input []ma.Multiaddr + output []ma.Multiaddr + }{ + { + name: "quic-filtered", + input: []ma.Multiaddr{q1, q1v1, q2, q2v1, q3}, + output: []ma.Multiaddr{q1v1, q2v1, q3}, + }, + { + name: "webtransport-filtered", + input: []ma.Multiaddr{q1, q1v1, wt1, wt2}, + output: []ma.Multiaddr{q1v1, wt2}, + }, + { + name: "all", + input: []ma.Multiaddr{q1, q1v1, wt1, q2, q2v1, wt2, t1, ws1}, + output: []ma.Multiaddr{q1v1, q2v1, t1}, + }, + { + name: "our-addrs-filtered", + input: append([]ma.Multiaddr{q1}, ourAddrs...), + output: []ma.Multiaddr{q1}, + }, + } + + ctx := context.Background() + p1 := test.RandPeerIDFatal(t) - require.Equal(t, []ma.Multiaddr{tcpAddr, quicAddr}, maybeRemoveWebTransportAddrs([]ma.Multiaddr{tcpAddr, quicAddr})) - require.Equal(t, []ma.Multiaddr{tcpAddr, webtransportAddr}, maybeRemoveWebTransportAddrs([]ma.Multiaddr{tcpAddr, webtransportAddr})) - require.Equal(t, []ma.Multiaddr{tcpAddr, quicAddr}, maybeRemoveWebTransportAddrs([]ma.Multiaddr{tcpAddr, webtransportAddr, quicAddr})) - require.Equal(t, []ma.Multiaddr{quicAddr}, maybeRemoveWebTransportAddrs([]ma.Multiaddr{quicAddr, webtransportAddr})) - require.Equal(t, []ma.Multiaddr{webtransportAddr}, maybeRemoveWebTransportAddrs([]ma.Multiaddr{webtransportAddr})) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + s.Peerstore().ClearAddrs(p1) + s.Peerstore().AddAddrs(p1, tc.input, peerstore.PermanentAddrTTL) + result, err := s.addrsForDial(ctx, p1) + require.NoError(t, err) + sort.Slice(result, func(i, j int) bool { return bytes.Compare(result[i].Bytes(), result[j].Bytes()) < 0 }) + sort.Slice(tc.output, func(i, j int) bool { return bytes.Compare(tc.output[i].Bytes(), tc.output[j].Bytes()) < 0 }) + if len(result) != len(tc.output) { + t.Fatalf("output mismatch got: %s want: %s", result, tc.output) + } + for i := 0; i < len(result); i++ { + if !result[i].Equal(tc.output[i]) { + t.Fatalf("output mismatch got: %s want: %s", result, tc.output) + } + } + }) + } } -func TestRemoveQuicDraft29(t *testing.T) { - tcpAddr := ma.StringCast("/ip4/9.5.6.4/tcp/1234") - quicDraft29Addr := ma.StringCast("/ip4/1.2.3.4/udp/443/quic") - quicV1Addr := ma.StringCast("/ip4/1.2.3.4/udp/443/quic-v1") +func TestBlackHoledAddrBlocked(t *testing.T) { + resolver, err := madns.NewResolver() + if err != nil { + t.Fatal(err) + } + s := newTestSwarmWithResolver(t, resolver) + defer s.Close() + + n := 3 + s.bhd.ipv6 = &blackHoleFilter{n: n, minSuccesses: 1, name: "IPv6"} + + // all dials to the address will fail. RFC6666 Discard Prefix + addr := ma.StringCast("/ip6/0100::1/tcp/54321/") - require.Equal(t, []ma.Multiaddr{tcpAddr, quicV1Addr}, maybeRemoveQUICDraft29([]ma.Multiaddr{tcpAddr, quicV1Addr})) - require.Equal(t, []ma.Multiaddr{tcpAddr, quicDraft29Addr}, maybeRemoveQUICDraft29([]ma.Multiaddr{tcpAddr, quicDraft29Addr})) - require.Equal(t, []ma.Multiaddr{tcpAddr, quicV1Addr}, maybeRemoveQUICDraft29([]ma.Multiaddr{tcpAddr, quicDraft29Addr, quicV1Addr})) - require.Equal(t, []ma.Multiaddr{quicV1Addr}, maybeRemoveQUICDraft29([]ma.Multiaddr{quicV1Addr, quicDraft29Addr})) - require.Equal(t, []ma.Multiaddr{quicDraft29Addr}, maybeRemoveQUICDraft29([]ma.Multiaddr{quicDraft29Addr})) + p, err := test.RandPeerID() + if err != nil { + t.Error(err) + } + s.Peerstore().AddAddr(p, addr, peerstore.PermanentAddrTTL) + + // do 1 extra dial to ensure that the blackHoleDetector state is updated since it + // happens in a different goroutine + for i := 0; i < n+1; i++ { + s.backf.Clear(p) + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + conn, err := s.DialPeer(ctx, p) + if err == nil || conn != nil { + t.Fatalf("expected dial to fail") + } + cancel() + } + s.backf.Clear(p) + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + conn, err := s.DialPeer(ctx, p) + if conn != nil { + t.Fatalf("expected dial to be blocked") + } + if err != ErrNoGoodAddresses { + t.Fatalf("expected to receive an error of type *DialError, got %s of type %T", err, err) + } } diff --git a/p2p/net/swarm/swarm_event_test.go b/p2p/net/swarm/swarm_event_test.go index 7d4fb6bd5d..86d698d611 100644 --- a/p2p/net/swarm/swarm_event_test.go +++ b/p2p/net/swarm/swarm_event_test.go @@ -64,3 +64,52 @@ func TestConnectednessEventsSingleConn(t *testing.T) { checkEvent(t, sub1, event.EvtPeerConnectednessChanged{Peer: s2.LocalPeer(), Connectedness: network.NotConnected}) checkEvent(t, sub2, event.EvtPeerConnectednessChanged{Peer: s1.LocalPeer(), Connectedness: network.NotConnected}) } + +func TestNoDeadlockWhenConsumingConnectednessEvents(t *testing.T) { + dialerEventBus := eventbus.NewBus() + dialer := swarmt.GenSwarm(t, swarmt.OptDialOnly, swarmt.EventBus(dialerEventBus)) + defer dialer.Close() + + listener := swarmt.GenSwarm(t, swarmt.OptDialOnly) + addrsToListen := []ma.Multiaddr{ + ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"), + } + + if err := listener.Listen(addrsToListen...); err != nil { + t.Fatal(err) + } + listenedAddrs := listener.ListenAddresses() + + dialer.Peerstore().AddAddrs(listener.LocalPeer(), listenedAddrs, time.Hour) + + sub, err := dialerEventBus.Subscribe(new(event.EvtPeerConnectednessChanged)) + require.NoError(t, err) + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // A slow consumer + go func() { + for { + select { + case <-ctx.Done(): + return + case <-sub.Out(): + time.Sleep(100 * time.Millisecond) + // Do something with the swarm that needs the conns lock + _ = dialer.ConnsToPeer(listener.LocalPeer()) + time.Sleep(100 * time.Millisecond) + } + } + }() + + for i := 0; i < 10; i++ { + // Connect and disconnect to trigger a bunch of events + _, err := dialer.DialPeer(context.Background(), listener.LocalPeer()) + require.NoError(t, err) + dialer.ClosePeer(listener.LocalPeer()) + } + + // The test should finish without deadlocking +} diff --git a/p2p/net/swarm/swarm_metrics.go b/p2p/net/swarm/swarm_metrics.go index 95e4b78b88..28564e9e54 100644 --- a/p2p/net/swarm/swarm_metrics.go +++ b/p2p/net/swarm/swarm_metrics.go @@ -69,6 +69,46 @@ var ( }, []string{"transport", "security", "muxer", "early_muxer", "ip_version"}, ) + dialsPerPeer = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "dials_per_peer_total", + Help: "Number of addresses dialed per peer", + }, + []string{"outcome", "num_dials"}, + ) + dialRankingDelay = prometheus.NewHistogram( + prometheus.HistogramOpts{ + Namespace: metricNamespace, + Name: "dial_ranking_delay_seconds", + Help: "delay introduced by the dial ranking logic", + Buckets: []float64{0.001, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.75, 1, 2}, + }, + ) + blackHoleFilterState = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: metricNamespace, + Name: "black_hole_filter_state", + Help: "State of the black hole filter", + }, + []string{"name"}, + ) + blackHoleFilterSuccessFraction = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: metricNamespace, + Name: "black_hole_filter_success_fraction", + Help: "Fraction of successful dials among the last n requests", + }, + []string{"name"}, + ) + blackHoleFilterNextRequestAllowedAfter = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: metricNamespace, + Name: "black_hole_filter_next_request_allowed_after", + Help: "Number of requests after which the next request will be allowed", + }, + []string{"name"}, + ) collectors = []prometheus.Collector{ connsOpened, keyTypes, @@ -76,6 +116,11 @@ var ( dialError, connDuration, connHandshakeLatency, + dialsPerPeer, + dialRankingDelay, + blackHoleFilterSuccessFraction, + blackHoleFilterState, + blackHoleFilterNextRequestAllowedAfter, } ) @@ -84,6 +129,9 @@ type MetricsTracer interface { ClosedConnection(network.Direction, time.Duration, network.ConnectionState, ma.Multiaddr) CompletedHandshake(time.Duration, network.ConnectionState, ma.Multiaddr) FailedDialing(ma.Multiaddr, error) + DialCompleted(success bool, totalDials int) + DialRankingDelay(d time.Duration) + UpdatedBlackHoleFilterState(name string, state blackHoleState, nextProbeAfter int, successFraction float64) } type metricsTracer struct{} @@ -133,28 +181,13 @@ func appendConnectionState(tags []string, cs network.ConnectionState) []string { return tags } -func getIPVersion(addr ma.Multiaddr) string { - version := "unknown" - ma.ForEach(addr, func(c ma.Component) bool { - if c.Protocol().Code == ma.P_IP4 { - version = "ip4" - return false - } else if c.Protocol().Code == ma.P_IP6 { - version = "ip6" - return false - } - return true - }) - return version -} - func (m *metricsTracer) OpenedConnection(dir network.Direction, p crypto.PubKey, cs network.ConnectionState, laddr ma.Multiaddr) { tags := metricshelper.GetStringSlice() defer metricshelper.PutStringSlice(tags) *tags = append(*tags, metricshelper.GetDirection(dir)) *tags = appendConnectionState(*tags, cs) - *tags = append(*tags, getIPVersion(laddr)) + *tags = append(*tags, metricshelper.GetIPVersion(laddr)) connsOpened.WithLabelValues(*tags...).Inc() *tags = (*tags)[:0] @@ -169,7 +202,7 @@ func (m *metricsTracer) ClosedConnection(dir network.Direction, duration time.Du *tags = append(*tags, metricshelper.GetDirection(dir)) *tags = appendConnectionState(*tags, cs) - *tags = append(*tags, getIPVersion(laddr)) + *tags = append(*tags, metricshelper.GetIPVersion(laddr)) connsClosed.WithLabelValues(*tags...).Inc() connDuration.WithLabelValues(*tags...).Observe(duration.Seconds()) } @@ -179,19 +212,12 @@ func (m *metricsTracer) CompletedHandshake(t time.Duration, cs network.Connectio defer metricshelper.PutStringSlice(tags) *tags = appendConnectionState(*tags, cs) - *tags = append(*tags, getIPVersion(laddr)) + *tags = append(*tags, metricshelper.GetIPVersion(laddr)) connHandshakeLatency.WithLabelValues(*tags...).Observe(t.Seconds()) } -var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP} - func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, err error) { - var transport string - for _, t := range transports { - if _, err := addr.ValueForProtocol(t); err == nil { - transport = ma.ProtocolWithCode(t).Name - } - } + transport := metricshelper.GetTransport(addr) e := "other" if errors.Is(err, context.Canceled) { e = "canceled" @@ -210,6 +236,42 @@ func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, err error) { defer metricshelper.PutStringSlice(tags) *tags = append(*tags, transport, e) - *tags = append(*tags, getIPVersion(addr)) + *tags = append(*tags, metricshelper.GetIPVersion(addr)) dialError.WithLabelValues(*tags...).Inc() } + +func (m *metricsTracer) DialCompleted(success bool, totalDials int) { + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + if success { + *tags = append(*tags, "success") + } else { + *tags = append(*tags, "failed") + } + + numDialLabels := [...]string{"0", "1", "2", "3", "4", "5", ">=6"} + var numDials string + if totalDials < len(numDialLabels) { + numDials = numDialLabels[totalDials] + } else { + numDials = numDialLabels[len(numDialLabels)-1] + } + *tags = append(*tags, numDials) + dialsPerPeer.WithLabelValues(*tags...).Inc() +} + +func (m *metricsTracer) DialRankingDelay(d time.Duration) { + dialRankingDelay.Observe(d.Seconds()) +} + +func (m *metricsTracer) UpdatedBlackHoleFilterState(name string, state blackHoleState, + nextProbeAfter int, successFraction float64) { + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + + *tags = append(*tags, name) + + blackHoleFilterState.WithLabelValues(*tags...).Set(float64(state)) + blackHoleFilterSuccessFraction.WithLabelValues(*tags...).Set(successFraction) + blackHoleFilterNextRequestAllowedAfter.WithLabelValues(*tags...).Set(float64(nextProbeAfter)) +} diff --git a/p2p/net/swarm/swarm_metrics_test.go b/p2p/net/swarm/swarm_metrics_test.go index 6b00da1a8a..25e13f3213 100644 --- a/p2p/net/swarm/swarm_metrics_test.go +++ b/p2p/net/swarm/swarm_metrics_test.go @@ -78,6 +78,9 @@ func TestMetricsNoAllocNoCover(t *testing.T) { ma.StringCast("/ip4/1.2.3.4/udp/2345"), } + bhfNames := []string{"udp", "ipv6", "tcp", "icmp"} + bhfState := []blackHoleState{blackHoleStateAllowed, blackHoleStateBlocked} + tests := map[string]func(){ "OpenedConnection": func() { mt.OpenedConnection(randItem(directions), randItem(keys), randItem(connections), randItem(addrs)) @@ -88,7 +91,17 @@ func TestMetricsNoAllocNoCover(t *testing.T) { "CompletedHandshake": func() { mt.CompletedHandshake(time.Duration(mrand.Intn(100))*time.Second, randItem(connections), randItem(addrs)) }, - "FailedDialing": func() { mt.FailedDialing(randItem(addrs), randItem(errors)) }, + "FailedDialing": func() { mt.FailedDialing(randItem(addrs), randItem(errors)) }, + "DialCompleted": func() { mt.DialCompleted(mrand.Intn(2) == 1, mrand.Intn(10)) }, + "DialRankingDelay": func() { mt.DialRankingDelay(time.Duration(mrand.Intn(1e10))) }, + "UpdatedBlackHoleFilterState": func() { + mt.UpdatedBlackHoleFilterState( + randItem(bhfNames), + randItem(bhfState), + mrand.Intn(100), + mrand.Float64(), + ) + }, } for method, f := range tests { diff --git a/p2p/protocol/holepunch/holepunch_test.go b/p2p/protocol/holepunch/holepunch_test.go index 9cf57ff65c..29d589cd7a 100644 --- a/p2p/protocol/holepunch/holepunch_test.go +++ b/p2p/protocol/holepunch/holepunch_test.go @@ -102,6 +102,10 @@ func TestNoHolePunchIfDirectConnExists(t *testing.T) { } func TestDirectDialWorks(t *testing.T) { + if race.WithRace() { + t.Skip("modifying manet.Private4 is racy") + } + // mark all addresses as public cpy := manet.Private4 manet.Private4 = []*net.IPNet{} diff --git a/p2p/protocol/holepunch/holepuncher.go b/p2p/protocol/holepunch/holepuncher.go index 49c39f5845..b651bd7822 100644 --- a/p2p/protocol/holepunch/holepuncher.go +++ b/p2p/protocol/holepunch/holepuncher.go @@ -101,10 +101,8 @@ func (hp *holePuncher) DirectConnect(p peer.ID) error { func (hp *holePuncher) directConnect(rp peer.ID) error { // short-circuit check to see if we already have a direct connection - for _, c := range hp.host.Network().ConnsToPeer(rp) { - if !isRelayAddress(c.RemoteMultiaddr()) { - return nil - } + if getDirectConnection(hp.host, rp) != nil { + return nil } // short-circuit hole punching if a direct dial works. @@ -133,8 +131,8 @@ func (hp *holePuncher) directConnect(rp peer.ID) error { log.Debugw("got inbound proxy conn", "peer", rp) // hole punch - for i := 0; i < maxRetries; i++ { - addrs, rtt, err := hp.initiateHolePunch(rp) + for i := 1; i <= maxRetries; i++ { + addrs, obsAddrs, rtt, err := hp.initiateHolePunch(rp) if err != nil { log.Debugw("hole punching failed", "peer", rp, "error", err) hp.tracer.ProtocolError(rp, err) @@ -159,44 +157,48 @@ func (hp *holePuncher) directConnect(rp peer.ID) error { hp.tracer.EndHolePunch(rp, dt, err) if err == nil { log.Debugw("hole punching with successful", "peer", rp, "time", dt) + hp.tracer.HolePunchFinished("initiator", i, addrs, obsAddrs, getDirectConnection(hp.host, rp)) return nil } case <-hp.ctx.Done(): timer.Stop() return hp.ctx.Err() } + if i == maxRetries { + hp.tracer.HolePunchFinished("initiator", maxRetries, addrs, obsAddrs, nil) + } } return fmt.Errorf("all retries for hole punch with peer %s failed", rp) } // initiateHolePunch opens a new hole punching coordination stream, // exchanges the addresses and measures the RTT. -func (hp *holePuncher) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, time.Duration, error) { +func (hp *holePuncher) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, []ma.Multiaddr, time.Duration, error) { hpCtx := network.WithUseTransient(hp.ctx, "hole-punch") sCtx := network.WithNoDial(hpCtx, "hole-punch") str, err := hp.host.NewStream(sCtx, rp, Protocol) if err != nil { - return nil, 0, fmt.Errorf("failed to open hole-punching stream: %w", err) + return nil, nil, 0, fmt.Errorf("failed to open hole-punching stream: %w", err) } defer str.Close() - addr, rtt, err := hp.initiateHolePunchImpl(str) + addr, obsAddr, rtt, err := hp.initiateHolePunchImpl(str) if err != nil { log.Debugf("%s", err) str.Reset() - return addr, rtt, err + return addr, obsAddr, rtt, err } - return addr, rtt, err + return addr, obsAddr, rtt, err } -func (hp *holePuncher) initiateHolePunchImpl(str network.Stream) ([]ma.Multiaddr, time.Duration, error) { +func (hp *holePuncher) initiateHolePunchImpl(str network.Stream) ([]ma.Multiaddr, []ma.Multiaddr, time.Duration, error) { if err := str.Scope().SetService(ServiceName); err != nil { - return nil, 0, fmt.Errorf("error attaching stream to holepunch service: %s", err) + return nil, nil, 0, fmt.Errorf("error attaching stream to holepunch service: %s", err) } if err := str.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil { - return nil, 0, fmt.Errorf("error reserving memory for stream: %s", err) + return nil, nil, 0, fmt.Errorf("error reserving memory for stream: %s", err) } defer str.Scope().ReleaseMemory(maxMsgSize) @@ -211,7 +213,7 @@ func (hp *holePuncher) initiateHolePunchImpl(str network.Stream) ([]ma.Multiaddr obsAddrs = hp.filter.FilterLocal(str.Conn().RemotePeer(), obsAddrs) } if len(obsAddrs) == 0 { - return nil, 0, errors.New("aborting hole punch initiation as we have no public address") + return nil, nil, 0, errors.New("aborting hole punch initiation as we have no public address") } start := time.Now() @@ -220,17 +222,17 @@ func (hp *holePuncher) initiateHolePunchImpl(str network.Stream) ([]ma.Multiaddr ObsAddrs: addrsToBytes(obsAddrs), }); err != nil { str.Reset() - return nil, 0, err + return nil, nil, 0, err } // wait for a CONNECT message from the remote peer var msg pb.HolePunch if err := rd.ReadMsg(&msg); err != nil { - return nil, 0, fmt.Errorf("failed to read CONNECT message from remote peer: %w", err) + return nil, nil, 0, fmt.Errorf("failed to read CONNECT message from remote peer: %w", err) } rtt := time.Since(start) if t := msg.GetType(); t != pb.HolePunch_CONNECT { - return nil, 0, fmt.Errorf("expect CONNECT message, got %s", t) + return nil, nil, 0, fmt.Errorf("expect CONNECT message, got %s", t) } addrs := removeRelayAddrs(addrsFromBytes(msg.ObsAddrs)) @@ -239,13 +241,13 @@ func (hp *holePuncher) initiateHolePunchImpl(str network.Stream) ([]ma.Multiaddr } if len(addrs) == 0 { - return nil, 0, errors.New("didn't receive any public addresses in CONNECT") + return nil, nil, 0, errors.New("didn't receive any public addresses in CONNECT") } if err := w.WriteMsg(&pb.HolePunch{Type: pb.HolePunch_SYNC.Enum()}); err != nil { - return nil, 0, fmt.Errorf("failed to send SYNC message for hole punching: %w", err) + return nil, nil, 0, fmt.Errorf("failed to send SYNC message for hole punching: %w", err) } - return addrs, rtt, nil + return addrs, obsAddrs, rtt, nil } func (hp *holePuncher) Close() error { diff --git a/p2p/protocol/holepunch/metrics.go b/p2p/protocol/holepunch/metrics.go new file mode 100644 index 0000000000..92ed20b14d --- /dev/null +++ b/p2p/protocol/holepunch/metrics.go @@ -0,0 +1,187 @@ +package holepunch + +import ( + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/p2p/metricshelper" + ma "github.com/multiformats/go-multiaddr" + "github.com/prometheus/client_golang/prometheus" +) + +const metricNamespace = "libp2p_holepunch" + +var ( + directDialsTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "direct_dials_total", + Help: "Direct Dials Total", + }, + []string{"outcome"}, + ) + hpAddressOutcomesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "address_outcomes_total", + Help: "Hole Punch outcomes by Transport", + }, + []string{"side", "num_attempts", "ipv", "transport", "outcome"}, + ) + hpOutcomesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricNamespace, + Name: "outcomes_total", + Help: "Hole Punch outcomes overall", + }, + []string{"side", "num_attempts", "outcome"}, + ) + + collectors = []prometheus.Collector{ + directDialsTotal, + hpAddressOutcomesTotal, + hpOutcomesTotal, + } +) + +type MetricsTracer interface { + HolePunchFinished(side string, attemptNum int, theirAddrs []ma.Multiaddr, ourAddr []ma.Multiaddr, directConn network.ConnMultiaddrs) + DirectDialFinished(success bool) +} + +type metricsTracer struct{} + +var _ MetricsTracer = &metricsTracer{} + +type metricsTracerSetting struct { + reg prometheus.Registerer +} + +type MetricsTracerOption func(*metricsTracerSetting) + +func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption { + return func(s *metricsTracerSetting) { + if reg != nil { + s.reg = reg + } + } +} + +func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer { + setting := &metricsTracerSetting{reg: prometheus.DefaultRegisterer} + for _, opt := range opts { + opt(setting) + } + metricshelper.RegisterCollectors(setting.reg, collectors...) + // initialise metrics's labels so that the first data point is handled correctly + for _, side := range []string{"initiator", "receiver"} { + for _, numAttempts := range []string{"1", "2", "3", "4"} { + for _, outcome := range []string{"success", "failed", "cancelled", "no_suitable_address"} { + for _, ipv := range []string{"ip4", "ip6"} { + for _, transport := range []string{"quic", "quic-v1", "tcp", "webtransport"} { + hpAddressOutcomesTotal.WithLabelValues(side, numAttempts, ipv, transport, outcome) + } + } + if outcome == "cancelled" { + // not a valid outcome for the overall holepunch metric + continue + } + hpOutcomesTotal.WithLabelValues(side, numAttempts, outcome) + } + } + } + return &metricsTracer{} +} + +// HolePunchFinished tracks metrics completion of a holepunch. Metrics are tracked on +// a holepunch attempt level and on individual addresses involved in a holepunch. +// +// outcome for an address is computed as: +// +// - success: +// A direct connection was established with the peer using this address +// - cancelled: +// A direct connection was established with the peer but not using this address +// - failed: +// No direct connection was made to the peer and the peer reported an address +// with the same transport as this address +// - no_suitable_address: +// The peer reported no address with the same transport as this address +func (mt *metricsTracer) HolePunchFinished(side string, numAttempts int, + remoteAddrs []ma.Multiaddr, localAddrs []ma.Multiaddr, directConn network.ConnMultiaddrs) { + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + + *tags = append(*tags, side, getNumAttemptString(numAttempts)) + var dipv, dtransport string + if directConn != nil { + dipv = metricshelper.GetIPVersion(directConn.LocalMultiaddr()) + dtransport = metricshelper.GetTransport(directConn.LocalMultiaddr()) + } + + matchingAddressCount := 0 + // calculate holepunch outcome for all the addresses involved + for _, la := range localAddrs { + lipv := metricshelper.GetIPVersion(la) + ltransport := metricshelper.GetTransport(la) + + matchingAddress := false + for _, ra := range remoteAddrs { + ripv := metricshelper.GetIPVersion(ra) + rtransport := metricshelper.GetTransport(ra) + if ripv == lipv && rtransport == ltransport { + // the peer reported an address with the same transport + matchingAddress = true + matchingAddressCount++ + + *tags = append(*tags, ripv, rtransport) + if directConn != nil && dipv == ripv && dtransport == rtransport { + // the connection was made using this address + *tags = append(*tags, "success") + } else if directConn != nil { + // connection was made but not using this address + *tags = append(*tags, "cancelled") + } else { + // no connection was made + *tags = append(*tags, "failed") + } + hpAddressOutcomesTotal.WithLabelValues(*tags...).Inc() + *tags = (*tags)[:2] // 2 because we want to keep (side, numAttempts) + break + } + } + if !matchingAddress { + *tags = append(*tags, lipv, ltransport, "no_suitable_address") + hpAddressOutcomesTotal.WithLabelValues(*tags...).Inc() + *tags = (*tags)[:2] // 2 because we want to keep (side, numAttempts) + } + } + + outcome := "failed" + if directConn != nil { + outcome = "success" + } else if matchingAddressCount == 0 { + // there were no matching addresses, this attempt was going to fail + outcome = "no_suitable_address" + } + + *tags = append(*tags, outcome) + hpOutcomesTotal.WithLabelValues(*tags...).Inc() +} + +func getNumAttemptString(numAttempt int) string { + var attemptStr = [...]string{"0", "1", "2", "3", "4", "5"} + if numAttempt > 5 { + return "> 5" + } + return attemptStr[numAttempt] +} + +func (mt *metricsTracer) DirectDialFinished(success bool) { + tags := metricshelper.GetStringSlice() + defer metricshelper.PutStringSlice(tags) + if success { + *tags = append(*tags, "success") + } else { + *tags = append(*tags, "failed") + } + directDialsTotal.WithLabelValues(*tags...).Inc() +} diff --git a/p2p/protocol/holepunch/metrics_noalloc_test.go b/p2p/protocol/holepunch/metrics_noalloc_test.go new file mode 100644 index 0000000000..968354fd7d --- /dev/null +++ b/p2p/protocol/holepunch/metrics_noalloc_test.go @@ -0,0 +1,49 @@ +//go:build nocover + +package holepunch + +import ( + "math/rand" + "testing" + + "github.com/libp2p/go-libp2p/core/network" + ma "github.com/multiformats/go-multiaddr" +) + +func TestNoCoverNoAllocMetrics(t *testing.T) { + addrs1 := [][]ma.Multiaddr{ + { + ma.StringCast("/ip4/0.0.0.0/tcp/1"), + ma.StringCast("/ip4/1.2.3.4/udp/2/quic"), + }, + nil, + } + addrs2 := [][]ma.Multiaddr{ + { + ma.StringCast("/ip4/1.2.3.4/tcp/3"), + ma.StringCast("/ip4/1.2.3.4/udp/4/quic"), + }, + nil, + } + conns := []network.ConnMultiaddrs{ + &mockConnMultiaddrs{local: addrs1[0][0], remote: addrs2[0][0]}, + nil, + } + sides := []string{"initiator", "receiver"} + mt := NewMetricsTracer() + testcases := map[string]func(){ + "DirectDialFinished": func() { mt.DirectDialFinished(rand.Intn(2) == 1) }, + "HolePunchFinished": func() { + mt.HolePunchFinished(sides[rand.Intn(len(sides))], rand.Intn(maxRetries), addrs1[rand.Intn(len(addrs1))], + addrs2[rand.Intn(len(addrs2))], conns[rand.Intn(len(conns))]) + }, + } + for method, f := range testcases { + t.Run(method, func(t *testing.T) { + cnt := testing.AllocsPerRun(1000, f) + if cnt > 0 { + t.Errorf("%s Failed: expected 0 allocs got %0.2f", method, cnt) + } + }) + } +} diff --git a/p2p/protocol/holepunch/metrics_test.go b/p2p/protocol/holepunch/metrics_test.go new file mode 100644 index 0000000000..6d7bf160d5 --- /dev/null +++ b/p2p/protocol/holepunch/metrics_test.go @@ -0,0 +1,102 @@ +package holepunch + +import ( + "testing" + + "github.com/libp2p/go-libp2p/core/network" + ma "github.com/multiformats/go-multiaddr" + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" +) + +func getCounterValue(t *testing.T, counter *prometheus.CounterVec, labels ...string) int { + t.Helper() + m := &dto.Metric{} + if err := counter.WithLabelValues(labels...).Write(m); err != nil { + t.Errorf("failed to extract counter value %s", err) + return 0 + } + return int(*m.Counter.Value) + +} + +func TestHolePunchOutcomeCounter(t *testing.T) { + t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1") + t2 := ma.StringCast("/ip4/1.2.3.4/tcp/2") + + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + + type testcase struct { + name string + theirAddrs []ma.Multiaddr + ourAddrs []ma.Multiaddr + conn network.ConnMultiaddrs + result map[[3]string]int + } + testcases := []testcase{ + { + name: "connection success", + theirAddrs: []ma.Multiaddr{t1, q1}, + ourAddrs: []ma.Multiaddr{t2, q2}, + conn: &mockConnMultiaddrs{local: t1, remote: t2}, + result: map[[3]string]int{ + [...]string{"ip4", "tcp", "success"}: 1, + [...]string{"ip4", "quic", "cancelled"}: 1, + }, + }, + { + name: "connection failed", + theirAddrs: []ma.Multiaddr{t1}, + ourAddrs: []ma.Multiaddr{t2, q2}, + conn: nil, + result: map[[3]string]int{ + [...]string{"ip4", "tcp", "failed"}: 1, + [...]string{"ip4", "quic", "no_suitable_address"}: 1, + }, + }, + { + name: "no_suitable_address", + theirAddrs: []ma.Multiaddr{t1, q1}, + ourAddrs: []ma.Multiaddr{t2, q2, q1v1}, + conn: &mockConnMultiaddrs{local: q1, remote: q2}, + result: map[[3]string]int{ + [...]string{"ip4", "tcp", "cancelled"}: 1, + [...]string{"ip4", "quic", "failed"}: 0, + [...]string{"ip4", "quic", "success"}: 1, + [...]string{"ip4", "tcp", "success"}: 0, + [...]string{"ip4", "quic-v1", "no_suitable_address"}: 1, + }, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + reg := prometheus.NewRegistry() + hpAddressOutcomesTotal.Reset() + mt := NewMetricsTracer(WithRegisterer(reg)) + for _, side := range []string{"receiver", "initiator"} { + mt.HolePunchFinished(side, 1, tc.theirAddrs, tc.ourAddrs, tc.conn) + for labels, value := range tc.result { + v := getCounterValue(t, hpAddressOutcomesTotal, side, "1", labels[0], labels[1], labels[2]) + if v != value { + t.Errorf("Invalid metric value %s: expected: %d got: %d", labels, value, v) + } + } + } + }) + } +} + +type mockConnMultiaddrs struct { + local, remote ma.Multiaddr +} + +func (cma *mockConnMultiaddrs) LocalMultiaddr() ma.Multiaddr { + return cma.local +} + +func (cma *mockConnMultiaddrs) RemoteMultiaddr() ma.Multiaddr { + return cma.remote +} diff --git a/p2p/protocol/holepunch/svc.go b/p2p/protocol/holepunch/svc.go index 5de7c7cf30..47bf434fb1 100644 --- a/p2p/protocol/holepunch/svc.go +++ b/p2p/protocol/holepunch/svc.go @@ -84,6 +84,7 @@ func NewService(h host.Host, ids identify.IDService, opts ...Option) (*Service, return nil, err } } + s.tracer.Start() s.refCount.Add(1) go s.watchForPublicAddr() @@ -165,24 +166,24 @@ func (s *Service) Close() error { return err } -func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, addrs []ma.Multiaddr, err error) { +func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, remoteAddrs []ma.Multiaddr, ownAddrs []ma.Multiaddr, err error) { // sanity check: a hole punch request should only come from peers behind a relay if !isRelayAddress(str.Conn().RemoteMultiaddr()) { - return 0, nil, fmt.Errorf("received hole punch stream: %s", str.Conn().RemoteMultiaddr()) + return 0, nil, nil, fmt.Errorf("received hole punch stream: %s", str.Conn().RemoteMultiaddr()) } - ownAddrs := removeRelayAddrs(s.ids.OwnObservedAddrs()) + ownAddrs = removeRelayAddrs(s.ids.OwnObservedAddrs()) if s.filter != nil { ownAddrs = s.filter.FilterLocal(str.Conn().RemotePeer(), ownAddrs) } // If we can't tell the peer where to dial us, there's no point in starting the hole punching. if len(ownAddrs) == 0 { - return 0, nil, errors.New("rejecting hole punch request, as we don't have any public addresses") + return 0, nil, nil, errors.New("rejecting hole punch request, as we don't have any public addresses") } if err := str.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil { log.Debugf("error reserving memory for stream: %s, err") - return 0, nil, err + return 0, nil, nil, err } defer str.Scope().ReleaseMemory(maxMsgSize) @@ -195,10 +196,10 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, addr str.SetDeadline(time.Now().Add(StreamTimeout)) if err := rd.ReadMsg(msg); err != nil { - return 0, nil, fmt.Errorf("failed to read message from initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to read message from initator: %w", err) } if t := msg.GetType(); t != pb.HolePunch_CONNECT { - return 0, nil, fmt.Errorf("expected CONNECT message from initiator but got %d", t) + return 0, nil, nil, fmt.Errorf("expected CONNECT message from initiator but got %d", t) } obsDial := removeRelayAddrs(addrsFromBytes(msg.ObsAddrs)) @@ -208,7 +209,7 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, addr log.Debugw("received hole punch request", "peer", str.Conn().RemotePeer(), "addrs", obsDial) if len(obsDial) == 0 { - return 0, nil, errors.New("expected CONNECT message to contain at least one address") + return 0, nil, nil, errors.New("expected CONNECT message to contain at least one address") } // Write CONNECT message @@ -217,18 +218,18 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, addr msg.ObsAddrs = addrsToBytes(ownAddrs) tstart := time.Now() if err := wr.WriteMsg(msg); err != nil { - return 0, nil, fmt.Errorf("failed to write CONNECT message to initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to write CONNECT message to initator: %w", err) } // Read SYNC message msg.Reset() if err := rd.ReadMsg(msg); err != nil { - return 0, nil, fmt.Errorf("failed to read message from initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to read message from initator: %w", err) } if t := msg.GetType(); t != pb.HolePunch_SYNC { - return 0, nil, fmt.Errorf("expected SYNC message from initiator but got %d", t) + return 0, nil, nil, fmt.Errorf("expected SYNC message from initiator but got %d", t) } - return time.Since(tstart), obsDial, nil + return time.Since(tstart), obsDial, ownAddrs, nil } func (s *Service) handleNewStream(str network.Stream) { @@ -249,7 +250,7 @@ func (s *Service) handleNewStream(str network.Stream) { } rp := str.Conn().RemotePeer() - rtt, addrs, err := s.incomingHolePunch(str) + rtt, addrs, ownAddrs, err := s.incomingHolePunch(str) if err != nil { s.tracer.ProtocolError(rp, err) log.Debugw("error handling holepunching stream from", "peer", rp, "error", err) @@ -270,6 +271,7 @@ func (s *Service) handleNewStream(str network.Stream) { err = holePunchConnect(s.ctx, s.host, pi, false) dt := time.Since(start) s.tracer.EndHolePunch(rp, dt, err) + s.tracer.HolePunchFinished("receiver", 1, addrs, ownAddrs, getDirectConnection(s.host, rp)) } // DirectConnect is only exposed for testing purposes. diff --git a/p2p/protocol/holepunch/tracer.go b/p2p/protocol/holepunch/tracer.go index abf31829d0..82e0ebfc0f 100644 --- a/p2p/protocol/holepunch/tracer.go +++ b/p2p/protocol/holepunch/tracer.go @@ -2,10 +2,10 @@ package holepunch import ( "context" - "fmt" "sync" "time" + "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" @@ -16,27 +16,57 @@ const ( tracerCacheDuration = 5 * time.Minute ) -// WithTracer is a Service option that enables hole punching tracing -func WithTracer(tr EventTracer) Option { +// WithTracer enables holepunch tracing with EventTracer et +func WithTracer(et EventTracer) Option { return func(hps *Service) error { - t := &tracer{ - tr: tr, + hps.tracer = &tracer{ + et: et, + mt: nil, + self: hps.host.ID(), + peers: make(map[peer.ID]struct { + counter int + last time.Time + }), + } + return nil + } +} + +// WithMetricsTracer enables holepunch Tracing with MetricsTracer mt +func WithMetricsTracer(mt MetricsTracer) Option { + return func(hps *Service) error { + hps.tracer = &tracer{ + et: nil, + mt: mt, + self: hps.host.ID(), + peers: make(map[peer.ID]struct { + counter int + last time.Time + }), + } + return nil + } +} + +// WithMetricsAndEventTracer enables holepunch tracking with MetricsTracer and EventTracer +func WithMetricsAndEventTracer(mt MetricsTracer, et EventTracer) Option { + return func(hps *Service) error { + hps.tracer = &tracer{ + et: et, + mt: mt, self: hps.host.ID(), peers: make(map[peer.ID]struct { counter int last time.Time }), } - t.refCount.Add(1) - t.ctx, t.ctxCancel = context.WithCancel(context.Background()) - go t.gc() - hps.tracer = t return nil } } type tracer struct { - tr EventTracer + et EventTracer + mt MetricsTracer self peer.ID refCount sync.WaitGroup @@ -103,16 +133,22 @@ func (t *tracer) DirectDialSuccessful(p peer.ID, dt time.Duration) { return } - t.tr.Trace(&Event{ - Timestamp: time.Now().UnixNano(), - Peer: t.self, - Remote: p, - Type: DirectDialEvtT, - Evt: &DirectDialEvt{ - Success: true, - EllapsedTime: dt, - }, - }) + if t.et != nil { + t.et.Trace(&Event{ + Timestamp: time.Now().UnixNano(), + Peer: t.self, + Remote: p, + Type: DirectDialEvtT, + Evt: &DirectDialEvt{ + Success: true, + EllapsedTime: dt, + }, + }) + } + + if t.mt != nil { + t.mt.DirectDialFinished(true) + } } func (t *tracer) DirectDialFailed(p peer.ID, dt time.Duration, err error) { @@ -120,108 +156,110 @@ func (t *tracer) DirectDialFailed(p peer.ID, dt time.Duration, err error) { return } - t.tr.Trace(&Event{ - Timestamp: time.Now().UnixNano(), - Peer: t.self, - Remote: p, - Type: DirectDialEvtT, - Evt: &DirectDialEvt{ - Success: false, - EllapsedTime: dt, - Error: err.Error(), - }, - }) + if t.et != nil { + t.et.Trace(&Event{ + Timestamp: time.Now().UnixNano(), + Peer: t.self, + Remote: p, + Type: DirectDialEvtT, + Evt: &DirectDialEvt{ + Success: false, + EllapsedTime: dt, + Error: err.Error(), + }, + }) + } + + if t.mt != nil { + t.mt.DirectDialFinished(false) + } } func (t *tracer) ProtocolError(p peer.ID, err error) { - if t == nil { - return + if t != nil && t.et != nil { + t.et.Trace(&Event{ + Timestamp: time.Now().UnixNano(), + Peer: t.self, + Remote: p, + Type: ProtocolErrorEvtT, + Evt: &ProtocolErrorEvt{ + Error: err.Error(), + }, + }) } - - t.tr.Trace(&Event{ - Timestamp: time.Now().UnixNano(), - Peer: t.self, - Remote: p, - Type: ProtocolErrorEvtT, - Evt: &ProtocolErrorEvt{ - Error: err.Error(), - }, - }) } func (t *tracer) StartHolePunch(p peer.ID, obsAddrs []ma.Multiaddr, rtt time.Duration) { - if t == nil { - return - } + if t != nil && t.et != nil { + addrs := make([]string, 0, len(obsAddrs)) + for _, a := range obsAddrs { + addrs = append(addrs, a.String()) + } - addrs := make([]string, 0, len(obsAddrs)) - for _, a := range obsAddrs { - addrs = append(addrs, a.String()) + t.et.Trace(&Event{ + Timestamp: time.Now().UnixNano(), + Peer: t.self, + Remote: p, + Type: StartHolePunchEvtT, + Evt: &StartHolePunchEvt{ + RemoteAddrs: addrs, + RTT: rtt, + }, + }) } - - t.tr.Trace(&Event{ - Timestamp: time.Now().UnixNano(), - Peer: t.self, - Remote: p, - Type: StartHolePunchEvtT, - Evt: &StartHolePunchEvt{ - RemoteAddrs: addrs, - RTT: rtt, - }, - }) } func (t *tracer) EndHolePunch(p peer.ID, dt time.Duration, err error) { - if t == nil { - return - } + if t != nil && t.et != nil { + evt := &EndHolePunchEvt{ + Success: err == nil, + EllapsedTime: dt, + } + if err != nil { + evt.Error = err.Error() + } - evt := &EndHolePunchEvt{ - Success: err == nil, - EllapsedTime: dt, - } - if err != nil { - evt.Error = err.Error() + t.et.Trace(&Event{ + Timestamp: time.Now().UnixNano(), + Peer: t.self, + Remote: p, + Type: EndHolePunchEvtT, + Evt: evt, + }) } +} - t.tr.Trace(&Event{ - Timestamp: time.Now().UnixNano(), - Peer: t.self, - Remote: p, - Type: EndHolePunchEvtT, - Evt: evt, - }) +func (t *tracer) HolePunchFinished(side string, numAttempts int, theirAddrs []ma.Multiaddr, ourAddrs []ma.Multiaddr, directConn network.Conn) { + if t != nil && t.mt != nil { + t.mt.HolePunchFinished(side, numAttempts, theirAddrs, ourAddrs, directConn) + } } func (t *tracer) HolePunchAttempt(p peer.ID) { - if t == nil { - return + if t != nil && t.et != nil { + now := time.Now() + t.mutex.Lock() + attempt := t.peers[p] + attempt.counter++ + counter := attempt.counter + attempt.last = now + t.peers[p] = attempt + t.mutex.Unlock() + + t.et.Trace(&Event{ + Timestamp: now.UnixNano(), + Peer: t.self, + Remote: p, + Type: HolePunchAttemptEvtT, + Evt: &HolePunchAttemptEvt{Attempt: counter}, + }) } - - now := time.Now() - t.mutex.Lock() - attempt := t.peers[p] - attempt.counter++ - counter := attempt.counter - attempt.last = now - t.peers[p] = attempt - t.mutex.Unlock() - - t.tr.Trace(&Event{ - Timestamp: now.UnixNano(), - Peer: t.self, - Remote: p, - Type: HolePunchAttemptEvtT, - Evt: &HolePunchAttemptEvt{Attempt: counter}, - }) } +// gc cleans up the peers map. This is only run when tracer is initialised with a non nil +// EventTracer func (t *tracer) gc() { - defer func() { - fmt.Println("done") - t.refCount.Done() - }() - + defer t.refCount.Done() timer := time.NewTicker(tracerGCInterval) defer timer.Stop() @@ -242,12 +280,18 @@ func (t *tracer) gc() { } } -func (t *tracer) Close() error { - if t == nil { - return nil +func (t *tracer) Start() { + if t != nil && t.et != nil { + t.ctx, t.ctxCancel = context.WithCancel(context.Background()) + t.refCount.Add(1) + go t.gc() } +} - t.ctxCancel() - t.refCount.Wait() +func (t *tracer) Close() error { + if t != nil && t.et != nil { + t.ctxCancel() + t.refCount.Wait() + } return nil } diff --git a/p2p/protocol/holepunch/util.go b/p2p/protocol/holepunch/util.go index 825f855ee8..13013568fe 100644 --- a/p2p/protocol/holepunch/util.go +++ b/p2p/protocol/holepunch/util.go @@ -55,6 +55,15 @@ func addrsFromBytes(bzs [][]byte) []ma.Multiaddr { return addrs } +func getDirectConnection(h host.Host, p peer.ID) network.Conn { + for _, c := range h.Network().ConnsToPeer(p) { + if !isRelayAddress(c.RemoteMultiaddr()) { + return c + } + } + return nil +} + func holePunchConnect(ctx context.Context, host host.Host, pi peer.AddrInfo, isClient bool) error { holePunchCtx := network.WithSimultaneousConnect(ctx, isClient, "hole-punching") forceDirectConnCtx := network.WithForceDirectDial(holePunchCtx, "hole-punching") diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go index 4173f2bb79..69506e9b34 100644 --- a/p2p/protocol/identify/id.go +++ b/p2p/protocol/identify/id.go @@ -3,9 +3,9 @@ package identify import ( "bytes" "context" + "errors" "fmt" "io" - "sort" "sync" "time" @@ -42,14 +42,11 @@ const ( IDPush = "/ipfs/id/push/1.0.0" ) -const DefaultProtocolVersion = "ipfs/0.1.0" - const ServiceName = "libp2p.identify" const maxPushConcurrency = 32 -// StreamReadTimeout is the read timeout on all incoming Identify family streams. -var StreamReadTimeout = 60 * time.Second +var Timeout = 60 * time.Second // timeout on all incoming Identify interactions const ( legacyIDSize = 2 * 1024 // 2k Bytes @@ -189,16 +186,11 @@ func NewIDService(h host.Host, opts ...Option) (*idService, error) { userAgent = cfg.userAgent } - protocolVersion := DefaultProtocolVersion - if cfg.protocolVersion != "" { - protocolVersion = cfg.protocolVersion - } - ctx, cancel := context.WithCancel(context.Background()) s := &idService{ Host: h, UserAgent: userAgent, - ProtocolVersion: protocolVersion, + ProtocolVersion: cfg.protocolVersion, ctx: ctx, ctxCancel: cancel, conns: make(map[network.Conn]entry), @@ -416,11 +408,14 @@ func (ids *idService) IdentifyWait(c network.Conn) <-chan struct{} { } func (ids *idService) identifyConn(c network.Conn) error { - s, err := c.NewStream(network.WithUseTransient(context.TODO(), "identify")) + ctx, cancel := context.WithTimeout(context.Background(), Timeout) + defer cancel() + s, err := c.NewStream(network.WithUseTransient(ctx, "identify")) if err != nil { log.Debugw("error opening identify stream", "peer", c.RemotePeer(), "error", err) return err } + s.SetDeadline(time.Now().Add(Timeout)) if err := s.SetProtocol(ID); err != nil { log.Warnf("error setting identify protocol for stream: %s", err) @@ -439,6 +434,7 @@ func (ids *idService) identifyConn(c network.Conn) error { // handlePush handles incoming identify push streams func (ids *idService) handlePush(s network.Stream) { + s.SetDeadline(time.Now().Add(Timeout)) ids.handleIdentifyResponse(s, true) } @@ -500,8 +496,6 @@ func (ids *idService) handleIdentifyResponse(s network.Stream, isPush bool) erro } defer s.Scope().ReleaseMemory(signedIDSize) - _ = s.SetReadDeadline(time.Now().Add(StreamReadTimeout)) - c := s.Conn() r := pbio.NewDelimitedReader(s, signedIDSize) @@ -562,9 +556,9 @@ func readAllIDMessages(r pbio.Reader, finalMsg proto.Message) error { func (ids *idService) updateSnapshot() (updated bool) { addrs := ids.Host.Addrs() - sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) == -1 }) + slices.SortFunc(addrs, func(a, b ma.Multiaddr) bool { return bytes.Compare(a.Bytes(), b.Bytes()) == -1 }) protos := ids.Host.Mux().Protocols() - sort.Slice(protos, func(i, j int) bool { return protos[i] < protos[j] }) + slices.Sort(protos) snapshot := identifySnapshot{ addrs: addrs, protocols: protos, @@ -764,16 +758,18 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo ids.Host.Peerstore().UpdateAddrs(p, ttl, peerstore.TempAddrTTL) } - // add signed addrs if we have them and the peerstore supports them - cab, ok := peerstore.GetCertifiedAddrBook(ids.Host.Peerstore()) - if ok && signedPeerRecord != nil { - _, addErr := cab.ConsumePeerRecord(signedPeerRecord, ttl) - if addErr != nil { - log.Debugf("error adding signed addrs to peerstore: %v", addErr) + var addrs []ma.Multiaddr + if signedPeerRecord != nil { + signedAddrs, err := ids.consumeSignedPeerRecord(c.RemotePeer(), signedPeerRecord) + if err != nil { + log.Debugf("failed to consume signed peer record: %s", err) + } else { + addrs = signedAddrs } } else { - ids.Host.Peerstore().AddAddrs(p, lmaddrs, ttl) + addrs = lmaddrs } + ids.Host.Peerstore().AddAddrs(p, filterAddrs(addrs, c.RemoteMultiaddr()), ttl) // Finally, expire all temporary addrs. ids.Host.Peerstore().UpdateAddrs(p, peerstore.TempAddrTTL, 0) @@ -792,6 +788,34 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo ids.consumeReceivedPubKey(c, mes.PublicKey) } +func (ids *idService) consumeSignedPeerRecord(p peer.ID, signedPeerRecord *record.Envelope) ([]ma.Multiaddr, error) { + if signedPeerRecord.PublicKey == nil { + return nil, errors.New("missing pubkey") + } + id, err := peer.IDFromPublicKey(signedPeerRecord.PublicKey) + if err != nil { + return nil, fmt.Errorf("failed to derive peer ID: %s", err) + } + if id != p { + return nil, fmt.Errorf("received signed peer record envelope for unexpected peer ID. expected %s, got %s", p, id) + } + r, err := signedPeerRecord.Record() + if err != nil { + return nil, fmt.Errorf("failed to obtain record: %w", err) + } + rec, ok := r.(*peer.PeerRecord) + if !ok { + return nil, errors.New("not a peer record") + } + if rec.PeerID != p { + return nil, fmt.Errorf("received signed peer record for unexpected peer ID. expected %s, got %s", p, rec.PeerID) + } + // Don't put the signed peer record into the peer store. + // They're not used anywhere. + // All we care about are the addresses. + return rec.Addrs, nil +} + func (ids *idService) consumeReceivedPubKey(c network.Conn, kb []byte) { lp := c.LocalPeer() rp := c.RemotePeer() @@ -962,3 +986,17 @@ func (nn *netNotifiee) Disconnected(_ network.Network, c network.Conn) { func (nn *netNotifiee) Listen(n network.Network, a ma.Multiaddr) {} func (nn *netNotifiee) ListenClose(n network.Network, a ma.Multiaddr) {} + +// filterAddrs filters the address slice based on the remove multiaddr: +// * if it's a localhost address, no filtering is applied +// * if it's a local network address, all localhost addresses are filtered out +// * if it's a public address, all localhost and local network addresses are filtered out +func filterAddrs(addrs []ma.Multiaddr, remote ma.Multiaddr) []ma.Multiaddr { + if manet.IsIPLoopback(remote) { + return addrs + } + if manet.IsPrivateAddr(remote) { + return ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool { return !manet.IsIPLoopback(a) }) + } + return ma.FilterAddrs(addrs, manet.IsPublicAddr) +} diff --git a/p2p/protocol/identify/id_glass_test.go b/p2p/protocol/identify/id_glass_test.go index 3477d52da4..777cef01ed 100644 --- a/p2p/protocol/identify/id_glass_test.go +++ b/p2p/protocol/identify/id_glass_test.go @@ -2,13 +2,17 @@ package identify import ( "context" + "fmt" "testing" "time" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" + recordPb "github.com/libp2p/go-libp2p/core/record/pb" blhost "github.com/libp2p/go-libp2p/p2p/host/blank" swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" + "google.golang.org/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -82,3 +86,90 @@ func TestFastDisconnect(t *testing.T) { // double-check to make sure we didn't actually timeout somewhere. require.NoError(t, ctx.Err()) } + +func TestWrongSignedPeerRecord(t *testing.T) { + h1 := blhost.NewBlankHost(swarmt.GenSwarm(t)) + defer h1.Close() + ids, err := NewIDService(h1) + require.NoError(t, err) + ids.Start() + defer ids.Close() + + h2 := blhost.NewBlankHost(swarmt.GenSwarm(t)) + defer h2.Close() + ids2, err := NewIDService(h2) + require.NoError(t, err) + ids2.Start() + defer ids2.Close() + + h3 := blhost.NewBlankHost(swarmt.GenSwarm(t)) + defer h2.Close() + ids3, err := NewIDService(h3) + require.NoError(t, err) + ids3.Start() + defer ids3.Close() + + h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()}) + s, err := h2.NewStream(context.Background(), h1.ID(), IDPush) + require.NoError(t, err) + + err = ids3.sendIdentifyResp(s, true) + // This should fail because the peer record is signed by h3, not h2 + require.NoError(t, err) + time.Sleep(time.Second) + + require.Empty(t, h1.Peerstore().Addrs(h3.ID()), "h1 should not know about h3 since it was relayed over h2") +} + +func TestInvalidSignedPeerRecord(t *testing.T) { + h1 := blhost.NewBlankHost(swarmt.GenSwarm(t)) + defer h1.Close() + ids, err := NewIDService(h1) + require.NoError(t, err) + ids.Start() + defer ids.Close() + + h2 := blhost.NewBlankHost(swarmt.GenSwarm(t)) + defer h2.Close() + ids2, err := NewIDService(h2) + require.NoError(t, err) + // We don't want to start the identify service, we'll manage the messages h2 + // sends manually so we can tweak it + // ids2.Start() + + h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()}) + require.Empty(t, h1.Peerstore().Addrs(h2.ID())) + + s, err := h2.NewStream(context.Background(), h1.ID(), IDPush) + require.NoError(t, err) + + ids2.updateSnapshot() + ids2.currentSnapshot.Lock() + snapshot := ids2.currentSnapshot.snapshot + ids2.currentSnapshot.Unlock() + mes := ids2.createBaseIdentifyResponse(s.Conn(), &snapshot) + fmt.Println("Signed record is", snapshot.record) + marshalled, err := snapshot.record.Marshal() + require.NoError(t, err) + + var envPb recordPb.Envelope + err = proto.Unmarshal(marshalled, &envPb) + require.NoError(t, err) + + envPb.Signature = []byte("invalid") + + mes.SignedPeerRecord, err = proto.Marshal(&envPb) + require.NoError(t, err) + + err = ids2.writeChunkedIdentifyMsg(s, mes) + require.NoError(t, err) + fmt.Println("Done sending msg") + s.Close() + + // Wait a bit for h1 to process the message + time.Sleep(1 * time.Second) + + cab, ok := h1.Peerstore().(peerstore.CertifiedAddrBook) + require.True(t, ok) + require.Nil(t, cab.GetPeerRecord(h2.ID())) +} diff --git a/p2p/protocol/identify/id_test.go b/p2p/protocol/identify/id_test.go index 0bdaae033e..b18ba51ca5 100644 --- a/p2p/protocol/identify/id_test.go +++ b/p2p/protocol/identify/id_test.go @@ -29,56 +29,20 @@ import ( "github.com/libp2p/go-libp2p/p2p/protocol/identify/pb" mockClock "github.com/benbjohnson/clock" - logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-testing/race" "github.com/libp2p/go-msgio/pbio" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func init() { - logging.SetLogLevel("net/identify", "debug") -} - func testKnowsAddrs(t *testing.T, h host.Host, p peer.ID, expected []ma.Multiaddr) { t.Helper() require.True(t, assert.ElementsMatchf(t, expected, h.Peerstore().Addrs(p), fmt.Sprintf("%s did not have addr for %s", h.ID(), p))) } -func testHasCertifiedAddrs(t *testing.T, h host.Host, p peer.ID, expected []ma.Multiaddr) { - t.Helper() - cab, ok := peerstore.GetCertifiedAddrBook(h.Peerstore()) - if !ok { - t.Error("expected peerstore to implement CertifiedAddrBook") - } - recordEnvelope := cab.GetPeerRecord(p) - if recordEnvelope == nil { - if len(expected) == 0 { - return - } - t.Fatalf("peerstore has no signed record for peer %s", p) - } - r, err := recordEnvelope.Record() - if err != nil { - t.Error("Error unwrapping signed PeerRecord from envelope", err) - } - rec, ok := r.(*peer.PeerRecord) - if !ok { - t.Error("unexpected record type") - } - require.True(t, assert.ElementsMatchf(t, expected, rec.Addrs, fmt.Sprintf("%s did not have certified addr for %s", h.ID(), p))) -} - -func testHasProtocolVersions(t *testing.T, h host.Host, p peer.ID) { - v, err := h.Peerstore().Get(p, "ProtocolVersion") - if v == nil { - t.Error("no protocol version") - return - } - if v.(string) != identify.DefaultProtocolVersion { - t.Error("protocol mismatch", err) - } - v, err = h.Peerstore().Get(p, "AgentVersion") +func testHasAgentVersion(t *testing.T, h host.Host, p peer.ID) { + v, err := h.Peerstore().Get(p, "AgentVersion") if v.(string) != "github.com/libp2p/go-libp2p" { // this is the default user agent t.Error("agent version mismatch", err) } @@ -103,13 +67,6 @@ func testHasPublicKey(t *testing.T, h host.Host, p peer.ID, shouldBe ic.PubKey) } } -func getSignedRecord(t *testing.T, h host.Host, p peer.ID) *record.Envelope { - cab, ok := peerstore.GetCertifiedAddrBook(h.Peerstore()) - require.True(t, ok) - rec := cab.GetPeerRecord(p) - return rec -} - // we're using BlankHost in our tests, which doesn't automatically generate peer records // and emit address change events on the bus like BasicHost. // This generates a record, puts it in the peerstore and emits an addr change event @@ -199,9 +156,8 @@ func TestIDService(t *testing.T) { // the idService should be opened automatically, by the network. // what we should see now is that both peers know about each others listen addresses. t.Log("test peer1 has peer2 addrs correctly") - testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them - testHasCertifiedAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) // should have signed addrs also - testHasProtocolVersions(t, h1, h2p) + testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them + testHasAgentVersion(t, h1, h2p) testHasPublicKey(t, h1, h2p, h2.Peerstore().PubKey(h2p)) // h1 should have h2's public key // now, this wait we do have to do. it's the wait for the Listening side @@ -213,8 +169,7 @@ func TestIDService(t *testing.T) { // and the protocol versions. t.Log("test peer2 has peer1 addrs correctly") testKnowsAddrs(t, h2, h1p, h1.Addrs()) // has them - testHasCertifiedAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) - testHasProtocolVersions(t, h2, h1p) + testHasAgentVersion(t, h2, h1p) testHasPublicKey(t, h2, h1p, h1.Peerstore().PubKey(h1p)) // h1 should have h2's public key // Need both sides to actually notice that the connection has been closed. @@ -230,8 +185,6 @@ func TestIDService(t *testing.T) { // addresses don't immediately expire on disconnect, so we should still have them testKnowsAddrs(t, h2, h1p, h1.Addrs()) testKnowsAddrs(t, h1, h2p, h2.Addrs()) - testHasCertifiedAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) - testHasCertifiedAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) <-sentDisconnect1 <-sentDisconnect2 @@ -242,8 +195,6 @@ func TestIDService(t *testing.T) { clk.Add(time.Second) testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) - testHasCertifiedAddrs(t, h1, h2p, []ma.Multiaddr{}) - testHasCertifiedAddrs(t, h2, h1p, []ma.Multiaddr{}) // test that we received the "identify completed" event. select { @@ -489,7 +440,6 @@ func TestIdentifyPushOnAddrChange(t *testing.T) { waitForAddrInStream(t, h2AddrStream, lad, 10*time.Second, "h2 did not receive addr change") require.True(t, ma.Contains(h2.Peerstore().Addrs(h1p), lad)) - require.NotNil(t, getSignedRecord(t, h2, h1p)) // change addr on host2 and ensure host 1 gets a pus lad = ma.StringCast("/ip4/127.0.0.1/tcp/1235") @@ -502,7 +452,6 @@ func TestIdentifyPushOnAddrChange(t *testing.T) { waitForAddrInStream(t, h1AddrStream, lad, 10*time.Second, "h1 did not receive addr change") require.True(t, ma.Contains(h1.Peerstore().Addrs(h2p), lad)) - require.NotNil(t, getSignedRecord(t, h1, h2p)) // change addr on host2 again lad2 := ma.StringCast("/ip4/127.0.0.1/tcp/1236") @@ -514,7 +463,6 @@ func TestIdentifyPushOnAddrChange(t *testing.T) { waitForAddrInStream(t, h1AddrStream, lad2, 10*time.Second, "h1 did not receive addr change") require.True(t, ma.Contains(h1.Peerstore().Addrs(h2p), lad2)) - require.NotNil(t, getSignedRecord(t, h1, h2p)) } func TestUserAgent(t *testing.T) { @@ -613,6 +561,9 @@ func TestSendPush(t *testing.T) { } func TestLargeIdentifyMessage(t *testing.T) { + if race.WithRace() { + t.Skip("setting peerstore.RecentlyConnectedAddrTTL is racy") + } oldTTL := peerstore.RecentlyConnectedAddrTTL peerstore.RecentlyConnectedAddrTTL = 500 * time.Millisecond t.Cleanup(func() { peerstore.RecentlyConnectedAddrTTL = oldTTL }) @@ -668,9 +619,8 @@ func TestLargeIdentifyMessage(t *testing.T) { // the idService should be opened automatically, by the network. // what we should see now is that both peers know about each others listen addresses. t.Log("test peer1 has peer2 addrs correctly") - testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them - testHasCertifiedAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) // should have signed addrs also - testHasProtocolVersions(t, h1, h2p) + testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them + testHasAgentVersion(t, h1, h2p) testHasPublicKey(t, h1, h2p, h2.Peerstore().PubKey(h2p)) // h1 should have h2's public key // now, this wait we do have to do. it's the wait for the Listening side @@ -684,8 +634,7 @@ func TestLargeIdentifyMessage(t *testing.T) { // and the protocol versions. t.Log("test peer2 has peer1 addrs correctly") testKnowsAddrs(t, h2, h1p, h1.Addrs()) // has them - testHasCertifiedAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) - testHasProtocolVersions(t, h2, h1p) + testHasAgentVersion(t, h2, h1p) testHasPublicKey(t, h2, h1p, h1.Peerstore().PubKey(h1p)) // h1 should have h2's public key // Need both sides to actually notice that the connection has been closed. @@ -701,8 +650,6 @@ func TestLargeIdentifyMessage(t *testing.T) { // addresses don't immediately expire on disconnect, so we should still have them testKnowsAddrs(t, h2, h1p, h1.Addrs()) testKnowsAddrs(t, h1, h2p, h2.Addrs()) - testHasCertifiedAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) - testHasCertifiedAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) <-sentDisconnect1 <-sentDisconnect2 @@ -713,8 +660,6 @@ func TestLargeIdentifyMessage(t *testing.T) { clk.Add(time.Second) testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) - testHasCertifiedAddrs(t, h1, h2p, []ma.Multiaddr{}) - testHasCertifiedAddrs(t, h2, h1p, []ma.Multiaddr{}) // test that we received the "identify completed" event. select { @@ -778,7 +723,6 @@ func TestLargePushMessage(t *testing.T) { require.Eventually(t, func() bool { return ma.Contains(h2.Peerstore().Addrs(h1p), lad) }, time.Second, 10*time.Millisecond) - require.NotNil(t, getSignedRecord(t, h2, h1p)) // change addr on host2 and ensure host 1 gets a pus lad = ma.StringCast("/ip4/127.0.0.1/tcp/1235") @@ -789,7 +733,6 @@ func TestLargePushMessage(t *testing.T) { require.Eventually(t, func() bool { return ma.Contains(h1.Peerstore().Addrs(h2p), lad) }, time.Second, 10*time.Millisecond) - testHasCertifiedAddrs(t, h1, h2p, h2.Addrs()) // change addr on host2 again lad2 := ma.StringCast("/ip4/127.0.0.1/tcp/1236") @@ -800,14 +743,13 @@ func TestLargePushMessage(t *testing.T) { require.Eventually(t, func() bool { return ma.Contains(h1.Peerstore().Addrs(h2p), lad2) }, time.Second, 10*time.Millisecond) - testHasCertifiedAddrs(t, h2, h1p, h1.Addrs()) } func TestIdentifyResponseReadTimeout(t *testing.T) { - timeout := identify.StreamReadTimeout - identify.StreamReadTimeout = 100 * time.Millisecond + timeout := identify.Timeout + identify.Timeout = 100 * time.Millisecond defer func() { - identify.StreamReadTimeout = timeout + identify.Timeout = timeout }() ctx, cancel := context.WithCancel(context.Background()) @@ -850,10 +792,10 @@ func TestIdentifyResponseReadTimeout(t *testing.T) { } func TestIncomingIDStreamsTimeout(t *testing.T) { - timeout := identify.StreamReadTimeout - identify.StreamReadTimeout = 100 * time.Millisecond + timeout := identify.Timeout + identify.Timeout = 100 * time.Millisecond defer func() { - identify.StreamReadTimeout = timeout + identify.Timeout = timeout }() ctx, cancel := context.WithCancel(context.Background()) diff --git a/p2p/protocol/identify/obsaddr.go b/p2p/protocol/identify/obsaddr.go index 451af096d9..0412541f5d 100644 --- a/p2p/protocol/identify/obsaddr.go +++ b/p2p/protocol/identify/obsaddr.go @@ -3,10 +3,11 @@ package identify import ( "context" "fmt" - "sort" "sync" "time" + "golang.org/x/exp/slices" + "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" @@ -213,14 +214,10 @@ func (oas *ObservedAddrManager) filter(observedAddrs []*observedAddr) []ma.Multi // We prefer inbound connection observations over outbound. // For ties, we prefer the ones with more votes. - sort.Slice(s, func(i int, j int) bool { - first := s[i] - second := s[j] - + slices.SortFunc(s, func(first, second *observedAddr) bool { if first.numInbound > second.numInbound { return true } - return len(first.seenBy) > len(second.seenBy) }) @@ -378,6 +375,11 @@ func shouldRecordObservation(host addrsProvider, network listenAddrsProvider, co return false } + // Provided by NAT64 peers, these addresses are specific to the peer and not publicly routable + if manet.IsNAT64IPv4ConvertedIPv6Addr(observed) { + return false + } + // we should only use ObservedAddr when our connection's LocalAddr is one // of our ListenAddrs. If we Dial out using an ephemeral addr, knowing that // address's external mapping is not very useful because the port will not be diff --git a/p2p/protocol/identify/obsaddr_glass_test.go b/p2p/protocol/identify/obsaddr_glass_test.go index 497b08e0bd..f96d3a3576 100644 --- a/p2p/protocol/identify/obsaddr_glass_test.go +++ b/p2p/protocol/identify/obsaddr_glass_test.go @@ -4,6 +4,7 @@ package identify // can access internal types. import ( + "fmt" "testing" ma "github.com/multiformats/go-multiaddr" @@ -103,3 +104,50 @@ func TestShouldRecordObservationWithWebTransport(t *testing.T) { require.True(t, shouldRecordObservation(h, h, c, observedAddr)) } + +func TestShouldRecordObservationWithNAT64Addr(t *testing.T) { + listenAddr1 := ma.StringCast("/ip4/0.0.0.0/tcp/1234") + ifaceAddr1 := ma.StringCast("/ip4/10.0.0.2/tcp/4321") + listenAddr2 := ma.StringCast("/ip6/::/tcp/1234") + ifaceAddr2 := ma.StringCast("/ip6/1::1/tcp/4321") + + h := &mockHost{ + listenAddrs: []ma.Multiaddr{listenAddr1, listenAddr2}, + ifaceListenAddrs: []ma.Multiaddr{ifaceAddr1, ifaceAddr2}, + addrs: []ma.Multiaddr{listenAddr1, listenAddr2}, + } + c := &mockConn{ + local: listenAddr1, + remote: ma.StringCast("/ip4/1.2.3.6/tcp/4321"), + } + + cases := []struct { + addr ma.Multiaddr + want bool + failureReason string + }{ + { + addr: ma.StringCast("/ip4/1.2.3.4/tcp/1234"), + want: true, + failureReason: "IPv4 should be observed", + }, + { + addr: ma.StringCast("/ip6/1::4/tcp/1234"), + want: true, + failureReason: "public IPv6 address should be observed", + }, + { + addr: ma.StringCast("/ip6/64:ff9b::192.0.1.2/tcp/1234"), + want: false, + failureReason: "NAT64 IPv6 address shouldn't be observed", + }, + } + for i, tc := range cases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + + if shouldRecordObservation(h, h, c, tc.addr) != tc.want { + t.Fatalf("%s %s", tc.addr, tc.failureReason) + } + }) + } +} diff --git a/p2p/test/basichost/basic_host_test.go b/p2p/test/basichost/basic_host_test.go new file mode 100644 index 0000000000..6b010ed2aa --- /dev/null +++ b/p2p/test/basichost/basic_host_test.go @@ -0,0 +1,72 @@ +package basichost + +import ( + "context" + "fmt" + "testing" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" + "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestNoStreamOverTransientConnection(t *testing.T) { + h1, err := libp2p.New( + libp2p.NoListenAddrs, + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + h2, err := libp2p.New( + libp2p.NoListenAddrs, + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + relay1, err := libp2p.New() + require.NoError(t, err) + + _, err = relay.New(relay1) + require.NoError(t, err) + + relay1info := peer.AddrInfo{ + ID: relay1.ID(), + Addrs: relay1.Addrs(), + } + err = h1.Connect(context.Background(), relay1info) + require.NoError(t, err) + + err = h2.Connect(context.Background(), relay1info) + require.NoError(t, err) + + h2.SetStreamHandler("/testprotocol", func(s network.Stream) { + fmt.Println("testprotocol") + + // End the example + s.Close() + }) + + _, err = client.Reserve(context.Background(), h2, relay1info) + require.NoError(t, err) + + relayaddr := ma.StringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String()) + + h2Info := peer.AddrInfo{ + ID: h2.ID(), + Addrs: []ma.Multiaddr{relayaddr}, + } + err = h1.Connect(context.Background(), h2Info) + require.NoError(t, err) + + ctx := network.WithNoDial(context.Background(), "test") + _, err = h1.NewStream(ctx, h2.ID(), "/testprotocol") + + require.ErrorIs(t, err, network.ErrTransientConn) + + _, err = h1.NewStream(network.WithUseTransient(context.Background(), "test"), h2.ID(), "/testprotocol") + require.NoError(t, err) +} diff --git a/p2p/test/resource-manager/rcmgr_test.go b/p2p/test/resource-manager/rcmgr_test.go index c953c5c7b7..4cdd5f2f05 100644 --- a/p2p/test/resource-manager/rcmgr_test.go +++ b/p2p/test/resource-manager/rcmgr_test.go @@ -13,7 +13,6 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" - rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs" "github.com/stretchr/testify/require" ) @@ -318,14 +317,10 @@ func TestReadmeExample(t *testing.T) { // The resource manager expects a limiter, se we create one from our limits. limiter := rcmgr.NewFixedLimiter(limits) - // (Optional if you want metrics) Construct the OpenCensus metrics reporter. - str, err := rcmgrObs.NewStatsTraceReporter() - if err != nil { - panic(err) - } - + // Metrics are enabled by default. If you want to disable metrics, use the + // WithMetricsDisabled option // Initialize the resource manager - rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str)) + rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithMetricsDisabled()) if err != nil { panic(err) } @@ -335,6 +330,5 @@ func TestReadmeExample(t *testing.T) { if err != nil { panic(err) } - host.Close() } diff --git a/p2p/test/transport/rcmgr_test.go b/p2p/test/transport/rcmgr_test.go new file mode 100644 index 0000000000..378d1f9bab --- /dev/null +++ b/p2p/test/transport/rcmgr_test.go @@ -0,0 +1,141 @@ +package transport_integration + +import ( + "context" + "fmt" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + gomock "github.com/golang/mock/gomock" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + mocknetwork "github.com/libp2p/go-libp2p/core/network/mocks" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/p2p/protocol/identify" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" + "github.com/stretchr/testify/require" +) + +func TestResourceManagerIsUsed(t *testing.T) { + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + for _, testDialer := range []bool{true, false} { + t.Run(tc.Name+fmt.Sprintf(" test_dialer=%v", testDialer), func(t *testing.T) { + + var reservedMemory, releasedMemory atomic.Int32 + defer func() { + require.Equal(t, reservedMemory.Load(), releasedMemory.Load()) + require.NotEqual(t, 0, reservedMemory.Load()) + }() + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + rcmgr := mocknetwork.NewMockResourceManager(ctrl) + rcmgr.EXPECT().Close() + + var listener, dialer host.Host + var expectedPeer peer.ID + var expectedDir network.Direction + var expectedAddr interface{} + if testDialer { + listener = tc.HostGenerator(t, TransportTestCaseOpts{NoRcmgr: true}) + dialer = tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ResourceManager: rcmgr}) + expectedPeer = listener.ID() + expectedDir = network.DirOutbound + expectedAddr = listener.Addrs()[0] + } else { + listener = tc.HostGenerator(t, TransportTestCaseOpts{ResourceManager: rcmgr}) + dialer = tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, NoRcmgr: true}) + expectedPeer = dialer.ID() + expectedDir = network.DirInbound + expectedAddr = gomock.Any() + } + + expectFd := true + if strings.Contains(tc.Name, "QUIC") || strings.Contains(tc.Name, "WebTransport") { + expectFd = false + } + + peerScope := mocknetwork.NewMockPeerScope(ctrl) + peerScope.EXPECT().ReserveMemory(gomock.Any(), gomock.Any()).AnyTimes().Do(func(amount int, pri uint8) { + reservedMemory.Add(int32(amount)) + }) + peerScope.EXPECT().ReleaseMemory(gomock.Any()).AnyTimes().Do(func(amount int) { + releasedMemory.Add(int32(amount)) + }) + peerScope.EXPECT().BeginSpan().AnyTimes().DoAndReturn(func() (network.ResourceScopeSpan, error) { + s := mocknetwork.NewMockResourceScopeSpan(ctrl) + s.EXPECT().BeginSpan().AnyTimes().Return(mocknetwork.NewMockResourceScopeSpan(ctrl), nil) + // No need to track these memory reservations since we assert that Done is called + s.EXPECT().ReserveMemory(gomock.Any(), gomock.Any()) + s.EXPECT().Done() + return s, nil + }) + var calledSetPeer atomic.Bool + + connScope := mocknetwork.NewMockConnManagementScope(ctrl) + connScope.EXPECT().SetPeer(expectedPeer).Do(func(peer.ID) { + calledSetPeer.Store(true) + }) + connScope.EXPECT().PeerScope().AnyTimes().DoAndReturn(func() network.PeerScope { + if calledSetPeer.Load() { + return peerScope + } + return nil + }) + connScope.EXPECT().Done() + + var allStreamsDone sync.WaitGroup + + rcmgr.EXPECT().OpenConnection(expectedDir, expectFd, expectedAddr).Return(connScope, nil) + rcmgr.EXPECT().OpenStream(expectedPeer, gomock.Any()).AnyTimes().DoAndReturn(func(id peer.ID, dir network.Direction) (network.StreamManagementScope, error) { + allStreamsDone.Add(1) + streamScope := mocknetwork.NewMockStreamManagementScope(ctrl) + // No need to track these memory reservations since we assert that Done is called + streamScope.EXPECT().ReserveMemory(gomock.Any(), gomock.Any()).AnyTimes() + streamScope.EXPECT().ReleaseMemory(gomock.Any()).AnyTimes() + streamScope.EXPECT().BeginSpan().AnyTimes().DoAndReturn(func() (network.ResourceScopeSpan, error) { + s := mocknetwork.NewMockResourceScopeSpan(ctrl) + s.EXPECT().BeginSpan().AnyTimes().Return(mocknetwork.NewMockResourceScopeSpan(ctrl), nil) + s.EXPECT().Done() + return s, nil + }) + + streamScope.EXPECT().SetService(gomock.Any()).MaxTimes(1) + streamScope.EXPECT().SetProtocol(gomock.Any()) + + streamScope.EXPECT().Done().Do(func() { + allStreamsDone.Done() + }) + return streamScope, nil + }) + + require.NoError(t, dialer.Connect(context.Background(), peer.AddrInfo{ + ID: listener.ID(), + Addrs: listener.Addrs(), + })) + // Wait for any in progress identifies to finish. + // We shouldn't have to do this, but basic host currently + // always does an identify. + <-dialer.(interface{ IDService() identify.IDService }).IDService().IdentifyWait(dialer.Network().ConnsToPeer(listener.ID())[0]) + <-listener.(interface{ IDService() identify.IDService }).IDService().IdentifyWait(listener.Network().ConnsToPeer(dialer.ID())[0]) + <-ping.Ping(context.Background(), dialer, listener.ID()) + err := dialer.Network().ClosePeer(listener.ID()) + require.NoError(t, err) + + // Wait a bit for any pending .Adds before we call .Wait to avoid a data race. + // This shouldn't be necessary since it should be impossible + // for an OpenStream to happen *after* a ClosePeer, however + // in practice it does and leads to test flakiness. + time.Sleep(10 * time.Millisecond) + allStreamsDone.Wait() + dialer.Close() + listener.Close() + }) + } + }) + } +} diff --git a/p2p/test/transport/transport_test.go b/p2p/test/transport/transport_test.go index bb8912ade2..e960806444 100644 --- a/p2p/test/transport/transport_test.go +++ b/p2p/test/transport/transport_test.go @@ -4,10 +4,13 @@ import ( "bytes" "context" "crypto/rand" + "errors" "fmt" "io" "net" + "runtime" "sync" + "sync/atomic" "testing" "time" @@ -17,7 +20,6 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" "github.com/libp2p/go-libp2p/p2p/protocol/ping" "github.com/libp2p/go-libp2p/p2p/security/noise" @@ -31,9 +33,10 @@ type TransportTestCase struct { } type TransportTestCaseOpts struct { - NoListen bool - NoRcmgr bool - ConnGater connmgr.ConnectionGater + NoListen bool + NoRcmgr bool + ConnGater connmgr.ConnectionGater + ResourceManager network.ResourceManager } func transformOpts(opts TransportTestCaseOpts) []config.Option { @@ -45,6 +48,10 @@ func transformOpts(opts TransportTestCaseOpts) []config.Option { if opts.ConnGater != nil { libp2pOpts = append(libp2pOpts, libp2p.ConnectionGater(opts.ConnGater)) } + + if opts.ResourceManager != nil { + libp2pOpts = append(libp2pOpts, libp2p.ResourceManager(opts.ResourceManager)) + } return libp2pOpts } @@ -81,22 +88,6 @@ var transportsToTest = []TransportTestCase{ return h }, }, - { - Name: "TCP / Noise / mplex", - HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { - libp2pOpts := transformOpts(opts) - libp2pOpts = append(libp2pOpts, libp2p.Security(noise.ID, noise.New)) - libp2pOpts = append(libp2pOpts, libp2p.Muxer(mplex.ID, mplex.DefaultTransport)) - if opts.NoListen { - libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) - } else { - libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0")) - } - h, err := libp2p.New(libp2pOpts...) - require.NoError(t, err) - return h - }, - }, { Name: "WebSocket", HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { @@ -146,6 +137,8 @@ func TestPing(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), @@ -173,20 +166,22 @@ func TestBigPing(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), Addrs: h1.Addrs(), })) - h1.SetStreamHandler("/BIG-ping/1.0.0", func(s network.Stream) { + h1.SetStreamHandler("/big-ping", func(s network.Stream) { io.Copy(s, s) s.Close() }) errCh := make(chan error, 1) allocs := testing.AllocsPerRun(10, func() { - s, err := h2.NewStream(context.Background(), h1.ID(), "/BIG-ping/1.0.0") + s, err := h2.NewStream(context.Background(), h1.ID(), "/big-ping") require.NoError(t, err) defer s.Close() @@ -220,12 +215,87 @@ func TestBigPing(t *testing.T) { } } +// TestLotsOfDataManyStreams tests sending a lot of data on multiple streams. +func TestLotsOfDataManyStreams(t *testing.T) { + // Skip on windows because of https://github.com/libp2p/go-libp2p/issues/2341 + if runtime.GOOS == "windows" { + t.Skip("Skipping on windows because of https://github.com/libp2p/go-libp2p/issues/2341") + } + + // 64k buffer + const bufSize = 64 << 10 + sendBuf := [bufSize]byte{} + const totalStreams = 512 + const parallel = 8 + // Total sends are > 20MiB + require.Greater(t, len(sendBuf)*totalStreams, 20<<20) + t.Log("Total sends:", len(sendBuf)*totalStreams) + + // Fill with random bytes + _, err := rand.Read(sendBuf[:]) + require.NoError(t, err) + + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) + h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() + start := time.Now() + defer func() { + t.Log("Total time:", time.Since(start)) + }() + + require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ + ID: h1.ID(), + Addrs: h1.Addrs(), + })) + + h1.SetStreamHandler("/big-ping", func(s network.Stream) { + io.Copy(s, s) + s.Close() + }) + + sem := make(chan struct{}, parallel) + var wg sync.WaitGroup + for i := 0; i < totalStreams; i++ { + wg.Add(1) + sem <- struct{}{} + go func() { + defer wg.Done() + recvBuf := [bufSize]byte{} + defer func() { <-sem }() + + s, err := h2.NewStream(context.Background(), h1.ID(), "/big-ping") + require.NoError(t, err) + defer s.Close() + + _, err = s.Write(sendBuf[:]) + require.NoError(t, err) + s.CloseWrite() + + _, err = io.ReadFull(s, recvBuf[:]) + require.NoError(t, err) + require.Equal(t, sendBuf, recvBuf) + + _, err = s.Read([]byte{0}) + require.ErrorIs(t, err, io.EOF) + }() + } + + wg.Wait() + }) + } +} + func TestManyStreams(t *testing.T) { const streamCount = 128 for _, tc := range transportsToTest { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoRcmgr: true}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, NoRcmgr: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), @@ -278,11 +348,134 @@ func TestManyStreams(t *testing.T) { } } +// TestMoreStreamsThanOurLimits tests handling more streams than our and the +// peer's resource limits. It spawns 1024 Go routines that try to open a stream +// and send and receive data. If they encounter an error they'll try again after +// a sleep. If the transport is well behaved, eventually all Go routines will +// have sent and received a message. +func TestMoreStreamsThanOurLimits(t *testing.T) { + const streamCount = 1024 + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + listener := tc.HostGenerator(t, TransportTestCaseOpts{}) + dialer := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer listener.Close() + defer dialer.Close() + + require.NoError(t, dialer.Connect(context.Background(), peer.AddrInfo{ + ID: listener.ID(), + Addrs: listener.Addrs(), + })) + + var handledStreams atomic.Int32 + var sawFirstErr atomic.Bool + + semaphore := make(chan struct{}, streamCount) + // Start with a single stream at a time. If that works, we'll increase the number of concurrent streams. + semaphore <- struct{}{} + + listener.SetStreamHandler("echo", func(s network.Stream) { + io.Copy(s, s) + s.Close() + }) + + wg := sync.WaitGroup{} + wg.Add(streamCount) + errCh := make(chan error, 1) + var completedStreams atomic.Int32 + for i := 0; i < streamCount; i++ { + go func() { + <-semaphore + var didErr bool + defer wg.Done() + defer completedStreams.Add(1) + defer func() { + select { + case semaphore <- struct{}{}: + default: + } + if !didErr && !sawFirstErr.Load() { + // No error! We can add one more stream to our concurrency limit. + select { + case semaphore <- struct{}{}: + default: + } + } + }() + + var s network.Stream + var err error + // maxRetries is an arbitrary retry amount if there's any error. + maxRetries := streamCount * 4 + shouldRetry := func(err error) bool { + didErr = true + sawFirstErr.Store(true) + maxRetries-- + if maxRetries == 0 || len(errCh) > 0 { + select { + case errCh <- errors.New("max retries exceeded"): + default: + } + return false + } + return true + } + + for { + s, err = dialer.NewStream(context.Background(), listener.ID(), "echo") + if err != nil { + if shouldRetry(err) { + time.Sleep(50 * time.Millisecond) + continue + } + } + err = func(s network.Stream) error { + defer s.Close() + _, err = s.Write([]byte("hello")) + if err != nil { + return err + } + + err = s.CloseWrite() + if err != nil { + return err + } + + b, err := io.ReadAll(s) + if err != nil { + return err + } + if !bytes.Equal(b, []byte("hello")) { + return errors.New("received data does not match sent data") + } + handledStreams.Add(1) + + return nil + }(s) + if err != nil && shouldRetry(err) { + time.Sleep(50 * time.Millisecond) + continue + } + return + } + }() + } + wg.Wait() + close(errCh) + + require.NoError(t, <-errCh) + require.Equal(t, streamCount, int(handledStreams.Load())) + }) + } +} + func TestListenerStreamResets(t *testing.T) { for _, tc := range transportsToTest { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), @@ -310,6 +503,8 @@ func TestDialerStreamResets(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), @@ -339,6 +534,8 @@ func TestStreamReadDeadline(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ ID: h1.ID(), diff --git a/p2p/transport/quic/transport.go b/p2p/transport/quic/transport.go index f279aed755..aef3f4c9de 100644 --- a/p2p/transport/quic/transport.go +++ b/p2p/transport/quic/transport.go @@ -190,11 +190,11 @@ func (t *transport) holePunch(ctx context.Context, raddr ma.Multiaddr, p peer.ID if err != nil { return nil, err } - pconn, err := t.connManager.Dial(network, addr) + tr, err := t.connManager.TransportForDial(network, addr) if err != nil { return nil, err } - defer pconn.DecreaseCount() + defer tr.DecreaseCount() ctx, cancel := context.WithTimeout(ctx, HolePunchTimeout) defer cancel() @@ -227,7 +227,7 @@ loop: punchErr = err break } - if _, err := pconn.WriteTo(payload, addr); err != nil { + if _, err := tr.WriteTo(payload, addr); err != nil { punchErr = err break } diff --git a/p2p/transport/quicreuse/connmgr.go b/p2p/transport/quicreuse/connmgr.go index 0e2793eee7..c12b86671a 100644 --- a/p2p/transport/quicreuse/connmgr.go +++ b/p2p/transport/quicreuse/connmgr.go @@ -13,8 +13,6 @@ import ( quiclogging "github.com/quic-go/quic-go/logging" ) -var quicDialContext = quic.DialContext // so we can mock it in tests - type ConnManager struct { reuseUDP4 *reuse reuseUDP6 *reuse @@ -25,20 +23,24 @@ type ConnManager struct { serverConfig *quic.Config clientConfig *quic.Config - connsMu sync.Mutex - conns map[string]connListenerEntry + quicListenersMu sync.Mutex + quicListeners map[string]quicListenerEntry + + srk quic.StatelessResetKey + mt *metricsTracer } -type connListenerEntry struct { +type quicListenerEntry struct { refCount int - ln *connListener + ln *quicListener } func NewConnManager(statelessResetKey quic.StatelessResetKey, opts ...Option) (*ConnManager, error) { cm := &ConnManager{ enableReuseport: true, enableDraft29: true, - conns: make(map[string]connListenerEntry), + quicListeners: make(map[string]quicListenerEntry), + srk: statelessResetKey, } for _, o := range opts { if err := o(cm); err != nil { @@ -47,17 +49,19 @@ func NewConnManager(statelessResetKey quic.StatelessResetKey, opts ...Option) (* } quicConf := quicConfig.Clone() - quicConf.StatelessResetKey = &statelessResetKey - var tracers []quiclogging.Tracer - if qlogTracer != nil { - tracers = append(tracers, qlogTracer) - } if cm.enableMetrics { - tracers = append(tracers, newMetricsTracer()) + cm.mt = newMetricsTracer() } - if len(tracers) > 0 { - quicConf.Tracer = quiclogging.NewMultiplexedTracer(tracers...) + quicConf.Tracer = func(ctx context.Context, p quiclogging.Perspective, ci quic.ConnectionID) quiclogging.ConnectionTracer { + tracers := make([]quiclogging.ConnectionTracer, 0, 2) + if qlogTracerDir != "" { + tracers = append(tracers, qloggerForDir(qlogTracerDir, p, ci)) + } + if cm.mt != nil { + tracers = append(tracers, cm.mt.TracerForConnection(ctx, p, ci)) + } + return quiclogging.NewMultiplexedConnectionTracer(tracers...) } serverConfig := quicConf.Clone() if !cm.enableDraft29 { @@ -67,8 +71,8 @@ func NewConnManager(statelessResetKey quic.StatelessResetKey, opts ...Option) (* cm.clientConfig = quicConf cm.serverConfig = serverConfig if cm.enableReuseport { - cm.reuseUDP4 = newReuse() - cm.reuseUDP6 = newReuse() + cm.reuseUDP4 = newReuse(&statelessResetKey, cm.mt) + cm.reuseUDP6 = newReuse(&statelessResetKey, cm.mt) } return cm, nil } @@ -100,22 +104,22 @@ func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWi return nil, err } - c.connsMu.Lock() - defer c.connsMu.Unlock() + c.quicListenersMu.Lock() + defer c.quicListenersMu.Unlock() key := laddr.String() - entry, ok := c.conns[key] + entry, ok := c.quicListeners[key] if !ok { - conn, err := c.listen(netw, laddr) + tr, err := c.transportForListen(netw, laddr) if err != nil { return nil, err } - ln, err := newConnListener(conn, c.serverConfig, c.enableDraft29) + ln, err := newQuicListener(tr, c.serverConfig, c.enableDraft29) if err != nil { return nil, err } - key = conn.LocalAddr().String() - entry = connListenerEntry{ln: ln} + key = tr.LocalAddr().String() + entry = quicListenerEntry{ln: ln} } l, err := entry.ln.Add(tlsConf, allowWindowIncrease, func() { c.onListenerClosed(key) }) if err != nil { @@ -125,38 +129,42 @@ func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWi return nil, err } entry.refCount++ - c.conns[key] = entry + c.quicListeners[key] = entry return l, nil } func (c *ConnManager) onListenerClosed(key string) { - c.connsMu.Lock() - defer c.connsMu.Unlock() + c.quicListenersMu.Lock() + defer c.quicListenersMu.Unlock() - entry := c.conns[key] + entry := c.quicListeners[key] entry.refCount = entry.refCount - 1 if entry.refCount <= 0 { - delete(c.conns, key) + delete(c.quicListeners, key) entry.ln.Close() } else { - c.conns[key] = entry + c.quicListeners[key] = entry } } -func (c *ConnManager) listen(network string, laddr *net.UDPAddr) (pConn, error) { +func (c *ConnManager) transportForListen(network string, laddr *net.UDPAddr) (refCountedQuicTransport, error) { if c.enableReuseport { reuse, err := c.getReuse(network) if err != nil { return nil, err } - return reuse.Listen(network, laddr) + return reuse.TransportForListen(network, laddr) } - conn, err := net.ListenUDP(network, laddr) + conn, err := listenAndOptimize(network, laddr) if err != nil { return nil, err } - return &noreuseConn{conn}, nil + tr := &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn} + if c.mt != nil { + tr.Transport.Tracer = c.mt + } + return tr, nil } func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (quic.Connection, error) { @@ -164,7 +172,7 @@ func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf if err != nil { return nil, err } - netw, host, err := manet.DialArgs(raddr) + netw, _, err := manet.DialArgs(raddr) if err != nil { return nil, err } @@ -181,25 +189,25 @@ func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf return nil, errors.New("unknown QUIC version") } - pconn, err := c.Dial(netw, naddr) + tr, err := c.TransportForDial(netw, naddr) if err != nil { return nil, err } - conn, err := quicDialContext(ctx, pconn, naddr, host, tlsConf, quicConf) + conn, err := tr.Dial(ctx, naddr, tlsConf, quicConf) if err != nil { - pconn.DecreaseCount() + tr.DecreaseCount() return nil, err } return conn, nil } -func (c *ConnManager) Dial(network string, raddr *net.UDPAddr) (pConn, error) { +func (c *ConnManager) TransportForDial(network string, raddr *net.UDPAddr) (refCountedQuicTransport, error) { if c.enableReuseport { reuse, err := c.getReuse(network) if err != nil { return nil, err } - return reuse.Dial(network, raddr) + return reuse.TransportForDial(network, raddr) } var laddr *net.UDPAddr @@ -209,11 +217,16 @@ func (c *ConnManager) Dial(network string, raddr *net.UDPAddr) (pConn, error) { case "udp6": laddr = &net.UDPAddr{IP: net.IPv6zero, Port: 0} } - conn, err := net.ListenUDP(network, laddr) + conn, err := listenAndOptimize(network, laddr) if err != nil { return nil, err } - return &noreuseConn{conn}, nil + tr := &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn} + if c.mt != nil { + tr.Transport.Tracer = c.mt + } + + return tr, nil } func (c *ConnManager) Protocols() []int { @@ -232,3 +245,12 @@ func (c *ConnManager) Close() error { } return c.reuseUDP4.Close() } + +// listenAndOptimize same as net.ListenUDP, but also calls quic.OptimizeConn +func listenAndOptimize(network string, laddr *net.UDPAddr) (net.PacketConn, error) { + conn, err := net.ListenUDP(network, laddr) + if err != nil { + return nil, err + } + return quic.OptimizeConn(conn) +} diff --git a/p2p/transport/quicreuse/connmgr_test.go b/p2p/transport/quicreuse/connmgr_test.go index 59aad639bc..92c7e31250 100644 --- a/p2p/transport/quicreuse/connmgr_test.go +++ b/p2p/transport/quicreuse/connmgr_test.go @@ -4,18 +4,18 @@ import ( "context" "crypto/rand" "crypto/tls" - "errors" "fmt" "net" + "runtime" "testing" "time" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/transport" libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" "github.com/quic-go/quic-go" "github.com/stretchr/testify/require" ) @@ -26,12 +26,12 @@ func checkClosed(t *testing.T, cm *ConnManager) { continue } r.mutex.Lock() - for _, conn := range r.globalListeners { - require.Zero(t, conn.GetCount()) + for _, tr := range r.globalListeners { + require.Zero(t, tr.GetCount()) } - for _, conns := range r.unicast { - for _, conn := range conns { - require.Zero(t, conn.GetCount()) + for _, trs := range r.unicast { + for _, tr := range trs { + require.Zero(t, tr.GetCount()) } } r.mutex.Unlock() @@ -92,91 +92,85 @@ func testListenOnSameProto(t *testing.T, enableReuseport bool) { // The conn passed to quic-go should be a conn that quic-go can be // type-asserted to a UDPConn. That way, it can use all kinds of optimizations. func TestConnectionPassedToQUICForListening(t *testing.T) { - origQuicListen := quicListen - t.Cleanup(func() { quicListen = origQuicListen }) - - var conn net.PacketConn - quicListen = func(c net.PacketConn, _ *tls.Config, _ *quic.Config) (quic.Listener, error) { - conn = c - return nil, errors.New("listen error") + if runtime.GOOS == "windows" { + t.Skip("skipping on windows. Windows doesn't support these optimizations") } - cm, err := NewConnManager([32]byte{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() - _, err = cm.ListenQUIC(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"), &tls.Config{NextProtos: []string{"proto"}}, nil) - require.EqualError(t, err, "listen error") - require.NotNil(t, conn) - defer conn.Close() - if _, ok := conn.(quic.OOBCapablePacketConn); !ok { - t.Fatal("connection passed to quic-go cannot be type asserted to a *net.UDPConn") - } -} - -type mockFailAcceptListener struct { - addr net.Addr -} - -// Accept implements quic.Listener -func (l *mockFailAcceptListener) Accept(context.Context) (quic.Connection, error) { - return nil, fmt.Errorf("Some error") -} + raddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") -// Addr implements quic.Listener -func (l *mockFailAcceptListener) Addr() net.Addr { - return l.addr -} + naddr, _, err := FromQuicMultiaddr(raddr) + require.NoError(t, err) + netw, _, err := manet.DialArgs(raddr) + require.NoError(t, err) -// Close implements quic.Listener -func (l *mockFailAcceptListener) Close() error { - return nil + _, err = cm.ListenQUIC(raddr, &tls.Config{NextProtos: []string{"proto"}}, nil) + require.NoError(t, err) + quicTr, err := cm.transportForListen(netw, naddr) + require.NoError(t, err) + defer quicTr.Close() + if _, ok := quicTr.(*singleOwnerTransport).Transport.Conn.(quic.OOBCapablePacketConn); !ok { + t.Fatal("connection passed to quic-go cannot be type asserted to a *net.UDPConn") + } } -var _ quic.Listener = &mockFailAcceptListener{} - func TestAcceptErrorGetCleanedUp(t *testing.T) { - origQuicListen := quicListen - t.Cleanup(func() { quicListen = origQuicListen }) - - quicListen = func(c net.PacketConn, _ *tls.Config, _ *quic.Config) (quic.Listener, error) { - return &mockFailAcceptListener{ - addr: c.LocalAddr(), - }, nil - } + raddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") cm, err := NewConnManager([32]byte{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() - l, err := cm.ListenQUIC(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"), &tls.Config{NextProtos: []string{"proto"}}, nil) + originalNumberOfGoroutines := runtime.NumGoroutine() + t.Log("num goroutines:", originalNumberOfGoroutines) + + // This spawns a background goroutine for the listener + l, err := cm.ListenQUIC(raddr, &tls.Config{NextProtos: []string{"proto"}}, nil) require.NoError(t, err) - defer l.Close() - _, err = l.Accept(context.Background()) - require.ErrorIs(t, err, transport.ErrListenerClosed) + + // We spawned a goroutine for the listener + require.Greater(t, runtime.NumGoroutine(), originalNumberOfGoroutines) + l.Close() + + // Now make sure we have less goroutines than before + // Manually doing the same as require.Eventually, except avoiding adding a goroutine + goRoutinesCleanedUp := false + for i := 0; i < 50; i++ { + t.Log("num goroutines:", runtime.NumGoroutine()) + if runtime.NumGoroutine() <= originalNumberOfGoroutines { + goRoutinesCleanedUp = true + break + } + time.Sleep(100 * time.Millisecond) + } + + require.True(t, goRoutinesCleanedUp, "goroutines were not cleaned up") } // The connection passed to quic-go needs to be type-assertable to a net.UDPConn, // in order to enable features like batch processing and ECN. func TestConnectionPassedToQUICForDialing(t *testing.T) { - origQuicDialContext := quicDialContext - defer func() { quicDialContext = origQuicDialContext }() - - var conn net.PacketConn - quicDialContext = func(_ context.Context, c net.PacketConn, _ net.Addr, _ string, _ *tls.Config, _ *quic.Config) (quic.Connection, error) { - conn = c - return nil, errors.New("dial error") + if runtime.GOOS == "windows" { + t.Skip("skipping on windows. Windows doesn't support these optimizations") } - cm, err := NewConnManager([32]byte{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() - _, err = cm.DialQUIC(context.Background(), ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1"), &tls.Config{}, nil) - require.EqualError(t, err, "dial error") - require.NotNil(t, conn) - defer conn.Close() - if _, ok := conn.(quic.OOBCapablePacketConn); !ok { + raddr := ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1") + + naddr, _, err := FromQuicMultiaddr(raddr) + require.NoError(t, err) + netw, _, err := manet.DialArgs(raddr) + require.NoError(t, err) + + quicTr, err := cm.TransportForDial(netw, naddr) + + require.NoError(t, err, "dial error") + defer quicTr.Close() + if _, ok := quicTr.(*singleOwnerTransport).Transport.Conn.(quic.OOBCapablePacketConn); !ok { t.Fatal("connection passed to quic-go cannot be type asserted to a *net.UDPConn") } } @@ -210,7 +204,7 @@ func connectWithProtocol(t *testing.T, addr net.Addr, alpn string) (peer.ID, err cconn, err := net.ListenUDP("udp4", nil) tlsConf.NextProtos = []string{alpn} require.NoError(t, err) - c, err := quic.Dial(cconn, addr, "localhost", tlsConf, nil) + c, err := quic.Dial(context.Background(), cconn, addr, tlsConf, nil) if err != nil { return "", err } diff --git a/p2p/transport/quicreuse/listener.go b/p2p/transport/quicreuse/listener.go index e7c0101718..50b793451a 100644 --- a/p2p/transport/quicreuse/listener.go +++ b/p2p/transport/quicreuse/listener.go @@ -15,8 +15,6 @@ import ( "github.com/quic-go/quic-go" ) -var quicListen = quic.Listen // so we can mock it in tests - type Listener interface { Accept(context.Context) (quic.Connection, error) Addr() net.Addr @@ -30,34 +28,34 @@ type protoConf struct { allowWindowIncrease func(conn quic.Connection, delta uint64) bool } -type connListener struct { - l quic.Listener - conn pConn - running chan struct{} - addrs []ma.Multiaddr +type quicListener struct { + l *quic.Listener + transport refCountedQuicTransport + running chan struct{} + addrs []ma.Multiaddr protocolsMu sync.Mutex protocols map[string]protoConf } -func newConnListener(c pConn, quicConfig *quic.Config, enableDraft29 bool) (*connListener, error) { +func newQuicListener(tr refCountedQuicTransport, quicConfig *quic.Config, enableDraft29 bool) (*quicListener, error) { localMultiaddrs := make([]ma.Multiaddr, 0, 2) - a, err := ToQuicMultiaddr(c.LocalAddr(), quic.Version1) + a, err := ToQuicMultiaddr(tr.LocalAddr(), quic.Version1) if err != nil { return nil, err } localMultiaddrs = append(localMultiaddrs, a) if enableDraft29 { - a, err := ToQuicMultiaddr(c.LocalAddr(), quic.VersionDraft29) + a, err := ToQuicMultiaddr(tr.LocalAddr(), quic.VersionDraft29) if err != nil { return nil, err } localMultiaddrs = append(localMultiaddrs, a) } - cl := &connListener{ + cl := &quicListener{ protocols: map[string]protoConf{}, running: make(chan struct{}), - conn: c, + transport: tr, addrs: localMultiaddrs, } tlsConf := &tls.Config{ @@ -78,7 +76,7 @@ func newConnListener(c pConn, quicConfig *quic.Config, enableDraft29 bool) (*con } quicConf := quicConfig.Clone() quicConf.AllowConnectionWindowIncrease = cl.allowWindowIncrease - ln, err := quicListen(c, tlsConf, quicConf) + ln, err := tr.Listen(tlsConf, quicConf) if err != nil { return nil, err } @@ -87,7 +85,7 @@ func newConnListener(c pConn, quicConfig *quic.Config, enableDraft29 bool) (*con return cl, nil } -func (l *connListener) allowWindowIncrease(conn quic.Connection, delta uint64) bool { +func (l *quicListener) allowWindowIncrease(conn quic.Connection, delta uint64) bool { l.protocolsMu.Lock() defer l.protocolsMu.Unlock() @@ -98,7 +96,7 @@ func (l *connListener) allowWindowIncrease(conn quic.Connection, delta uint64) b return conf.allowWindowIncrease(conn, delta) } -func (l *connListener) Add(tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool, onRemove func()) (Listener, error) { +func (l *quicListener) Add(tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool, onRemove func()) (Listener, error) { l.protocolsMu.Lock() defer l.protocolsMu.Unlock() @@ -130,9 +128,9 @@ func (l *connListener) Add(tlsConf *tls.Config, allowWindowIncrease func(conn qu return ln, nil } -func (l *connListener) Run() error { +func (l *quicListener) Run() error { defer close(l.running) - defer l.conn.DecreaseCount() + defer l.transport.DecreaseCount() for { conn, err := l.l.Accept(context.Background()) if err != nil { @@ -154,7 +152,7 @@ func (l *connListener) Run() error { } } -func (l *connListener) Close() error { +func (l *quicListener) Close() error { err := l.l.Close() <-l.running // wait for Run to return return err diff --git a/p2p/transport/quicreuse/reuse.go b/p2p/transport/quicreuse/reuse.go index cc90038efe..1584b29254 100644 --- a/p2p/transport/quicreuse/reuse.go +++ b/p2p/transport/quicreuse/reuse.go @@ -1,29 +1,58 @@ package quicreuse import ( + "context" + "crypto/tls" "net" "sync" "time" "github.com/google/gopacket/routing" "github.com/libp2p/go-netroute" + "github.com/quic-go/quic-go" ) -type pConn interface { - net.PacketConn +type refCountedQuicTransport interface { + LocalAddr() net.Addr - // count conn reference + // Used to send packets directly around QUIC. Useful for hole punching. + WriteTo([]byte, net.Addr) (int, error) + + Close() error + + // count transport reference DecreaseCount() IncreaseCount() + + Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *quic.Config) (quic.Connection, error) + Listen(tlsConf *tls.Config, conf *quic.Config) (*quic.Listener, error) +} + +type singleOwnerTransport struct { + quic.Transport + + // Used to write packets directly around QUIC. + packetConn net.PacketConn } -type noreuseConn struct { - *net.UDPConn +func (c *singleOwnerTransport) IncreaseCount() {} +func (c *singleOwnerTransport) DecreaseCount() { + c.Transport.Close() } -func (c *noreuseConn) IncreaseCount() {} -func (c *noreuseConn) DecreaseCount() { - c.UDPConn.Close() +func (c *singleOwnerTransport) LocalAddr() net.Addr { + return c.Transport.Conn.LocalAddr() +} + +func (c *singleOwnerTransport) Close() error { + // TODO(when we drop support for go 1.19) use errors.Join + c.Transport.Close() + return c.packetConn.Close() +} + +func (c *singleOwnerTransport) WriteTo(b []byte, addr net.Addr) (int, error) { + // Safe because we called quic.OptimizeConn ourselves. + return c.packetConn.WriteTo(b, addr) } // Constant. Defined as variables to simplify testing. @@ -32,26 +61,40 @@ var ( maxUnusedDuration = 10 * time.Second ) -type reuseConn struct { - *net.UDPConn +type refcountedTransport struct { + quic.Transport + + // Used to write packets directly around QUIC. + packetConn net.PacketConn mutex sync.Mutex refCount int unusedSince time.Time } -func newReuseConn(conn *net.UDPConn) *reuseConn { - return &reuseConn{UDPConn: conn} -} - -func (c *reuseConn) IncreaseCount() { +func (c *refcountedTransport) IncreaseCount() { c.mutex.Lock() c.refCount++ c.unusedSince = time.Time{} c.mutex.Unlock() } -func (c *reuseConn) DecreaseCount() { +func (c *refcountedTransport) Close() error { + // TODO(when we drop support for go 1.19) use errors.Join + c.Transport.Close() + return c.packetConn.Close() +} + +func (c *refcountedTransport) WriteTo(b []byte, addr net.Addr) (int, error) { + // Safe because we called quic.OptimizeConn ourselves. + return c.packetConn.WriteTo(b, addr) +} + +func (c *refcountedTransport) LocalAddr() net.Addr { + return c.Transport.Conn.LocalAddr() +} + +func (c *refcountedTransport) DecreaseCount() { c.mutex.Lock() c.refCount-- if c.refCount == 0 { @@ -60,7 +103,7 @@ func (c *reuseConn) DecreaseCount() { c.mutex.Unlock() } -func (c *reuseConn) ShouldGarbageCollect(now time.Time) bool { +func (c *refcountedTransport) ShouldGarbageCollect(now time.Time) bool { c.mutex.Lock() defer c.mutex.Unlock() return !c.unusedSince.IsZero() && c.unusedSince.Add(maxUnusedDuration).Before(now) @@ -73,22 +116,27 @@ type reuse struct { gcStopChan chan struct{} routes routing.Router - unicast map[string] /* IP.String() */ map[int] /* port */ *reuseConn - // globalListeners contains connections that are listening on 0.0.0.0 / :: - globalListeners map[int]*reuseConn - // globalDialers contains connections that we've dialed out from. These connections are listening on 0.0.0.0 / :: - // On Dial, connections are reused from this map if no connection is available in the globalListeners - // On Listen, connections are reused from this map if the requested port is 0, and then moved to globalListeners - globalDialers map[int]*reuseConn + unicast map[string] /* IP.String() */ map[int] /* port */ *refcountedTransport + // globalListeners contains transports that are listening on 0.0.0.0 / :: + globalListeners map[int]*refcountedTransport + // globalDialers contains transports that we've dialed out from. These transports are listening on 0.0.0.0 / :: + // On Dial, transports are reused from this map if no transport is available in the globalListeners + // On Listen, transports are reused from this map if the requested port is 0, and then moved to globalListeners + globalDialers map[int]*refcountedTransport + + statelessResetKey *quic.StatelessResetKey + metricsTracer *metricsTracer } -func newReuse() *reuse { +func newReuse(srk *quic.StatelessResetKey, mt *metricsTracer) *reuse { r := &reuse{ - unicast: make(map[string]map[int]*reuseConn), - globalListeners: make(map[int]*reuseConn), - globalDialers: make(map[int]*reuseConn), - closeChan: make(chan struct{}), - gcStopChan: make(chan struct{}), + unicast: make(map[string]map[int]*refcountedTransport), + globalListeners: make(map[int]*refcountedTransport), + globalDialers: make(map[int]*refcountedTransport), + closeChan: make(chan struct{}), + gcStopChan: make(chan struct{}), + statelessResetKey: srk, + metricsTracer: mt, } go r.gc() return r @@ -97,15 +145,15 @@ func newReuse() *reuse { func (r *reuse) gc() { defer func() { r.mutex.Lock() - for _, conn := range r.globalListeners { - conn.Close() + for _, tr := range r.globalListeners { + tr.Close() } - for _, conn := range r.globalDialers { - conn.Close() + for _, tr := range r.globalDialers { + tr.Close() } - for _, conns := range r.unicast { - for _, conn := range conns { - conn.Close() + for _, trs := range r.unicast { + for _, tr := range trs { + tr.Close() } } r.mutex.Unlock() @@ -121,28 +169,28 @@ func (r *reuse) gc() { case <-ticker.C: now := time.Now() r.mutex.Lock() - for key, conn := range r.globalListeners { - if conn.ShouldGarbageCollect(now) { - conn.Close() + for key, tr := range r.globalListeners { + if tr.ShouldGarbageCollect(now) { + tr.Close() delete(r.globalListeners, key) } } - for key, conn := range r.globalDialers { - if conn.ShouldGarbageCollect(now) { - conn.Close() + for key, tr := range r.globalDialers { + if tr.ShouldGarbageCollect(now) { + tr.Close() delete(r.globalDialers, key) } } - for ukey, conns := range r.unicast { - for key, conn := range conns { - if conn.ShouldGarbageCollect(now) { - conn.Close() - delete(conns, key) + for ukey, trs := range r.unicast { + for key, tr := range trs { + if tr.ShouldGarbageCollect(now) { + tr.Close() + delete(trs, key) } } - if len(conns) == 0 { + if len(trs) == 0 { delete(r.unicast, ukey) - // If we've dropped all connections with a unicast binding, + // If we've dropped all transports with a unicast binding, // assume our routes may have changed. if len(r.unicast) == 0 { r.routes = nil @@ -158,7 +206,7 @@ func (r *reuse) gc() { } } -func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) { +func (r *reuse) TransportForDial(network string, raddr *net.UDPAddr) (*refcountedTransport, error) { var ip *net.IP // Only bother looking up the source address if we actually _have_ non 0.0.0.0 listeners. @@ -178,37 +226,37 @@ func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) { r.mutex.Lock() defer r.mutex.Unlock() - conn, err := r.dialLocked(network, ip) + tr, err := r.transportForDialLocked(network, ip) if err != nil { return nil, err } - conn.IncreaseCount() - return conn, nil + tr.IncreaseCount() + return tr, nil } -func (r *reuse) dialLocked(network string, source *net.IP) (*reuseConn, error) { +func (r *reuse) transportForDialLocked(network string, source *net.IP) (*refcountedTransport, error) { if source != nil { - // We already have at least one suitable connection... - if conns, ok := r.unicast[source.String()]; ok { + // We already have at least one suitable transport... + if trs, ok := r.unicast[source.String()]; ok { // ... we don't care which port we're dialing from. Just use the first. - for _, c := range conns { - return c, nil + for _, tr := range trs { + return tr, nil } } } - // Use a connection listening on 0.0.0.0 (or ::). + // Use a transport listening on 0.0.0.0 (or ::). // Again, we don't care about the port number. - for _, conn := range r.globalListeners { - return conn, nil + for _, tr := range r.globalListeners { + return tr, nil } - // Use a connection we've previously dialed from - for _, conn := range r.globalDialers { - return conn, nil + // Use a transport we've previously dialed from + for _, tr := range r.globalDialers { + return tr, nil } - // We don't have a connection that we can use for dialing. + // We don't have a transport that we can use for dialing. // Dial a new connection from a random port. var addr *net.UDPAddr switch network { @@ -217,69 +265,81 @@ func (r *reuse) dialLocked(network string, source *net.IP) (*reuseConn, error) { case "udp6": addr = &net.UDPAddr{IP: net.IPv6zero, Port: 0} } - conn, err := net.ListenUDP(network, addr) + conn, err := listenAndOptimize(network, addr) if err != nil { return nil, err } - rconn := newReuseConn(conn) - r.globalDialers[conn.LocalAddr().(*net.UDPAddr).Port] = rconn - return rconn, nil + tr := &refcountedTransport{Transport: quic.Transport{ + Conn: conn, + StatelessResetKey: r.statelessResetKey, + }, packetConn: conn} + if r.metricsTracer != nil { + tr.Transport.Tracer = r.metricsTracer + } + r.globalDialers[conn.LocalAddr().(*net.UDPAddr).Port] = tr + return tr, nil } -func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) { +func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcountedTransport, error) { r.mutex.Lock() defer r.mutex.Unlock() - // Check if we can reuse a connection we have already dialed out from. - // We reuse a connection from globalDialers when the requested port is 0 or the requested + // Check if we can reuse a transport we have already dialed out from. + // We reuse a transport from globalDialers when the requested port is 0 or the requested // port is already in the globalDialers. - // If we are reusing a connection from globalDialers, we move the globalDialers entry to + // If we are reusing a transport from globalDialers, we move the globalDialers entry to // globalListeners if laddr.IP.IsUnspecified() { - var rconn *reuseConn + var rTr *refcountedTransport var localAddr *net.UDPAddr if laddr.Port == 0 { - // the requested port is 0, we can reuse any connection - for _, conn := range r.globalDialers { - rconn = conn - localAddr = rconn.UDPConn.LocalAddr().(*net.UDPAddr) + // the requested port is 0, we can reuse any transport + for _, tr := range r.globalDialers { + rTr = tr + localAddr = rTr.LocalAddr().(*net.UDPAddr) delete(r.globalDialers, localAddr.Port) break } } else if _, ok := r.globalDialers[laddr.Port]; ok { - rconn = r.globalDialers[laddr.Port] - localAddr = rconn.UDPConn.LocalAddr().(*net.UDPAddr) + rTr = r.globalDialers[laddr.Port] + localAddr = rTr.LocalAddr().(*net.UDPAddr) delete(r.globalDialers, localAddr.Port) } // found a match - if rconn != nil { - rconn.IncreaseCount() - r.globalListeners[localAddr.Port] = rconn - return rconn, nil + if rTr != nil { + rTr.IncreaseCount() + r.globalListeners[localAddr.Port] = rTr + return rTr, nil } } - conn, err := net.ListenUDP(network, laddr) + conn, err := listenAndOptimize(network, laddr) if err != nil { return nil, err } localAddr := conn.LocalAddr().(*net.UDPAddr) - rconn := newReuseConn(conn) + tr := &refcountedTransport{Transport: quic.Transport{ + Conn: conn, + StatelessResetKey: r.statelessResetKey, + }, packetConn: conn} + if r.metricsTracer != nil { + tr.Transport.Tracer = r.metricsTracer + } - rconn.IncreaseCount() + tr.IncreaseCount() // Deal with listen on a global address if localAddr.IP.IsUnspecified() { // The kernel already checked that the laddr is not already listen // so we need not check here (when we create ListenUDP). - r.globalListeners[localAddr.Port] = rconn - return rconn, nil + r.globalListeners[localAddr.Port] = tr + return tr, nil } // Deal with listen on a unicast address if _, ok := r.unicast[localAddr.IP.String()]; !ok { - r.unicast[localAddr.IP.String()] = make(map[int]*reuseConn) + r.unicast[localAddr.IP.String()] = make(map[int]*refcountedTransport) // Assume the system's routes may have changed if we're adding a new listener. // Ignore the error, there's nothing we can do. r.routes, _ = netroute.New() @@ -287,8 +347,8 @@ func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) { // The kernel already checked that the laddr is not already listen // so we need not check here (when we create ListenUDP). - r.unicast[localAddr.IP.String()][localAddr.Port] = rconn - return rconn, nil + r.unicast[localAddr.IP.String()][localAddr.Port] = tr + return tr, nil } func (r *reuse) Close() error { diff --git a/p2p/transport/quicreuse/reuse_test.go b/p2p/transport/quicreuse/reuse_test.go index 0cd62f0d51..b373f31fe4 100644 --- a/p2p/transport/quicreuse/reuse_test.go +++ b/p2p/transport/quicreuse/reuse_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" ) -func (c *reuseConn) GetCount() int { +func (c *refcountedTransport) GetCount() int { c.mutex.Lock() defer c.mutex.Unlock() return c.refCount @@ -21,20 +21,20 @@ func (c *reuseConn) GetCount() int { func closeAllConns(reuse *reuse) { reuse.mutex.Lock() - for _, conn := range reuse.globalListeners { - for conn.GetCount() > 0 { - conn.DecreaseCount() + for _, tr := range reuse.globalListeners { + for tr.GetCount() > 0 { + tr.DecreaseCount() } } - for _, conn := range reuse.globalDialers { - for conn.GetCount() > 0 { - conn.DecreaseCount() + for _, tr := range reuse.globalDialers { + for tr.GetCount() > 0 { + tr.DecreaseCount() } } - for _, conns := range reuse.unicast { - for _, conn := range conns { - for conn.GetCount() > 0 { - conn.DecreaseCount() + for _, trs := range reuse.unicast { + for _, tr := range trs { + for tr.GetCount() > 0 { + tr.DecreaseCount() } } } @@ -61,36 +61,37 @@ func cleanup(t *testing.T, reuse *reuse) { } func TestReuseListenOnAllIPv4(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) require.Eventually(t, isGarbageCollectorRunning, 500*time.Millisecond, 50*time.Millisecond, "expected garbage collector to be running") cleanup(t, reuse) addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") require.NoError(t, err) - conn, err := reuse.Listen("udp4", addr) + conn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) require.Equal(t, conn.GetCount(), 1) } func TestReuseListenOnAllIPv6(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) require.Eventually(t, isGarbageCollectorRunning, 500*time.Millisecond, 50*time.Millisecond, "expected garbage collector to be running") cleanup(t, reuse) addr, err := net.ResolveUDPAddr("udp6", "[::]:1234") require.NoError(t, err) - conn, err := reuse.Listen("udp6", addr) + tr, err := reuse.TransportForListen("udp6", addr) require.NoError(t, err) - require.Equal(t, conn.GetCount(), 1) + defer tr.Close() + require.Equal(t, tr.GetCount(), 1) } func TestReuseCreateNewGlobalConnOnDial(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) addr, err := net.ResolveUDPAddr("udp4", "1.1.1.1:1234") require.NoError(t, err) - conn, err := reuse.Dial("udp4", addr) + conn, err := reuse.TransportForDial("udp4", addr) require.NoError(t, err) require.Equal(t, conn.GetCount(), 1) laddr := conn.LocalAddr().(*net.UDPAddr) @@ -99,65 +100,65 @@ func TestReuseCreateNewGlobalConnOnDial(t *testing.T) { } func TestReuseConnectionWhenDialing(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") require.NoError(t, err) - lconn, err := reuse.Listen("udp4", addr) + lconn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) require.Equal(t, lconn.GetCount(), 1) // dial raddr, err := net.ResolveUDPAddr("udp4", "1.1.1.1:1234") require.NoError(t, err) - conn, err := reuse.Dial("udp4", raddr) + conn, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) require.Equal(t, conn.GetCount(), 2) } func TestReuseConnectionWhenListening(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) raddr, err := net.ResolveUDPAddr("udp4", "1.1.1.1:1234") require.NoError(t, err) - conn, err := reuse.Dial("udp4", raddr) + tr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - laddr := &net.UDPAddr{IP: net.IPv4zero, Port: conn.UDPConn.LocalAddr().(*net.UDPAddr).Port} - lconn, err := reuse.Listen("udp4", laddr) + laddr := &net.UDPAddr{IP: net.IPv4zero, Port: tr.LocalAddr().(*net.UDPAddr).Port} + lconn, err := reuse.TransportForListen("udp4", laddr) require.NoError(t, err) require.Equal(t, lconn.GetCount(), 2) - require.Equal(t, conn.GetCount(), 2) + require.Equal(t, tr.GetCount(), 2) } func TestReuseConnectionWhenDialBeforeListen(t *testing.T) { - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) // dial any address raddr, err := net.ResolveUDPAddr("udp4", "1.1.1.1:1234") require.NoError(t, err) - rconn, err := reuse.Dial("udp4", raddr) + rTr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) // open a listener laddr := &net.UDPAddr{IP: net.IPv4zero, Port: 1234} - lconn, err := reuse.Listen("udp4", laddr) + lTr, err := reuse.TransportForListen("udp4", laddr) require.NoError(t, err) // new dials should go via the listener connection raddr, err = net.ResolveUDPAddr("udp4", "1.1.1.1:1235") require.NoError(t, err) - conn, err := reuse.Dial("udp4", raddr) + tr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, conn, lconn) - require.Equal(t, conn.GetCount(), 2) + require.Equal(t, tr, lTr) + require.Equal(t, tr.GetCount(), 2) // a listener on an unspecified port should reuse the dialer laddr2 := &net.UDPAddr{IP: net.IPv4zero, Port: 0} - lconn2, err := reuse.Listen("udp4", laddr2) + lconn2, err := reuse.TransportForListen("udp4", laddr2) require.NoError(t, err) - require.Equal(t, lconn2, rconn) + require.Equal(t, lconn2, rTr) require.Equal(t, lconn2.GetCount(), 2) } @@ -165,7 +166,7 @@ func TestReuseListenOnSpecificInterface(t *testing.T) { if platformHasRoutingTables() { t.Skip("this test only works on platforms that support routing tables") } - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) router, err := netroute.New() @@ -178,11 +179,11 @@ func TestReuseListenOnSpecificInterface(t *testing.T) { // listen addr, err := net.ResolveUDPAddr("udp4", ip.String()+":0") require.NoError(t, err) - lconn, err := reuse.Listen("udp4", addr) + lconn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) require.Equal(t, lconn.GetCount(), 1) // dial - conn, err := reuse.Dial("udp4", raddr) + conn, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) require.Equal(t, conn.GetCount(), 1) } @@ -202,7 +203,7 @@ func TestReuseGarbageCollect(t *testing.T) { maxUnusedDuration = 10 * maxUnusedDuration } - reuse := newReuse() + reuse := newReuse(nil, nil) cleanup(t, reuse) numGlobals := func() int { @@ -213,19 +214,19 @@ func TestReuseGarbageCollect(t *testing.T) { raddr, err := net.ResolveUDPAddr("udp4", "1.2.3.4:1234") require.NoError(t, err) - dconn, err := reuse.Dial("udp4", raddr) + dTr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, dconn.GetCount(), 1) + require.Equal(t, dTr.GetCount(), 1) addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:1234") require.NoError(t, err) - lconn, err := reuse.Listen("udp4", addr) + lTr, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) - require.Equal(t, lconn.GetCount(), 1) + require.Equal(t, lTr.GetCount(), 1) closeTime := time.Now() - lconn.DecreaseCount() - dconn.DecreaseCount() + lTr.DecreaseCount() + dTr.DecreaseCount() for { num := numGlobals() diff --git a/p2p/transport/quicreuse/tracer.go b/p2p/transport/quicreuse/tracer.go index 46a683cbce..1386a5c3d1 100644 --- a/p2p/transport/quicreuse/tracer.go +++ b/p2p/transport/quicreuse/tracer.go @@ -9,31 +9,28 @@ import ( golog "github.com/ipfs/go-log/v2" "github.com/klauspost/compress/zstd" + "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/logging" "github.com/quic-go/quic-go/qlog" ) var log = golog.Logger("quic-utils") -// QLOGTracer holds a qlog tracer, if qlogging is enabled (enabled using the QLOGDIR environment variable). -// Otherwise it is nil. -var qlogTracer logging.Tracer +// QLOGTracer holds a qlog tracer dir, if qlogging is enabled (enabled using the QLOGDIR environment variable). +// Otherwise it is an empty string. +var qlogTracerDir string func init() { - if qlogDir := os.Getenv("QLOGDIR"); len(qlogDir) > 0 { - qlogTracer = initQlogger(qlogDir) - } + qlogTracerDir = os.Getenv("QLOGDIR") } -func initQlogger(qlogDir string) logging.Tracer { - return qlog.NewTracer(func(role logging.Perspective, connID []byte) io.WriteCloser { - // create the QLOGDIR, if it doesn't exist - if err := os.MkdirAll(qlogDir, 0777); err != nil { - log.Errorf("creating the QLOGDIR failed: %s", err) - return nil - } - return newQlogger(qlogDir, role, connID) - }) +func qloggerForDir(qlogDir string, p logging.Perspective, ci quic.ConnectionID) logging.ConnectionTracer { + // create the QLOGDIR, if it doesn't exist + if err := os.MkdirAll(qlogDir, 0777); err != nil { + log.Errorf("creating the QLOGDIR failed: %s", err) + return nil + } + return qlog.NewConnectionTracer(newQlogger(qlogDir, p, ci), p, ci) } // The qlogger logs qlog events to a temporary file: .