diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6e548e238e2..4bbfa5be9bd 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -27,6 +27,15 @@ jobs: with: cache: true go-version-file: go.mod + - name: Increase UDP buffer sizes (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + sudo sysctl -w net.core.rmem_max=7500000 + sudo sysctl -w net.core.wmem_max=7500000 + - name: Increase UDP buffer sizes (macOS) + if: matrix.os == 'macos-latest' + run: | + sudo sysctl -w kern.ipc.maxsockbuf=6291456 - name: Build run: make build - name: Test with race detector (Ubuntu and MacOS) diff --git a/.gitignore b/.gitignore index b7b0629ab25..c94f81d64ab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.idea /.vscode /tmp +/vendor # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o diff --git a/cmd/bee/cmd/cmd.go b/cmd/bee/cmd/cmd.go index 5b2c156c630..9324d58012f 100644 --- a/cmd/bee/cmd/cmd.go +++ b/cmd/bee/cmd/cmd.go @@ -17,6 +17,7 @@ import ( "github.com/ethersphere/bee/v2/pkg/log" "github.com/ethersphere/bee/v2/pkg/node" "github.com/ethersphere/bee/v2/pkg/swarm" + p2pforge "github.com/ipshipyard/p2p-forge/client" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -82,6 +83,12 @@ const ( optionReserveCapacityDoubling = "reserve-capacity-doubling" optionSkipPostageSnapshot = "skip-postage-snapshot" optionNameMinimumGasTipCap = "minimum-gas-tip-cap" + optionNameP2PWSSEnable = "p2p-wss-enable" + optionP2PWSSAddr = "p2p-wss-addr" + optionNATWSSAddr = "nat-wss-addr" + optionAutoTLSDomain = "autotls-domain" + optionAutoTLSRegistrationEndpoint = "autotls-registration-endpoint" + optionAutoTLSCAEndpoint = "autotls-ca-endpoint" ) // nolint:gochecknoinits @@ -292,6 +299,12 @@ func (c *command) setAllFlags(cmd *cobra.Command) { cmd.Flags().Int(optionReserveCapacityDoubling, 0, "reserve capacity doubling") cmd.Flags().Bool(optionSkipPostageSnapshot, false, "skip postage snapshot") cmd.Flags().Uint64(optionNameMinimumGasTipCap, 0, "minimum gas tip cap in wei for transactions, 0 means use suggested gas tip cap") + cmd.Flags().Bool(optionNameP2PWSSEnable, false, "Enable Secure WebSocket P2P connections") + cmd.Flags().String(optionP2PWSSAddr, ":1635", "p2p wss address") + cmd.Flags().String(optionNATWSSAddr, "", "WSS NAT exposed address") + cmd.Flags().String(optionAutoTLSDomain, p2pforge.DefaultForgeDomain, "autotls domain") + cmd.Flags().String(optionAutoTLSRegistrationEndpoint, p2pforge.DefaultForgeEndpoint, "autotls registration endpoint") + cmd.Flags().String(optionAutoTLSCAEndpoint, p2pforge.DefaultCAEndpoint, "autotls certificate authority endpoint") } func newLogger(cmd *cobra.Command, verbosity string) (log.Logger, error) { diff --git a/cmd/bee/cmd/start.go b/cmd/bee/cmd/start.go index c6662bcba57..9633b9bd6f1 100644 --- a/cmd/bee/cmd/start.go +++ b/cmd/bee/cmd/start.go @@ -281,12 +281,16 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo Addr: c.config.GetString(optionNameP2PAddr), AllowPrivateCIDRs: c.config.GetBool(optionNameAllowPrivateCIDRs), APIAddr: c.config.GetString(optionNameAPIAddr), + EnableWSS: c.config.GetBool(optionNameP2PWSSEnable), + WSSAddr: c.config.GetString(optionP2PWSSAddr), + AutoTLSStorageDir: filepath.Join(c.config.GetString(optionNameDataDir), "autotls"), BlockchainRpcEndpoint: c.config.GetString(optionNameBlockchainRpcEndpoint), BlockProfile: c.config.GetBool(optionNamePProfBlock), BlockTime: networkConfig.blockTime, BootnodeMode: bootNode, Bootnodes: networkConfig.bootNodes, CacheCapacity: c.config.GetUint64(optionNameCacheCapacity), + AutoTLSCAEndpoint: c.config.GetString(optionAutoTLSCAEndpoint), ChainID: networkConfig.chainID, ChequebookEnable: c.config.GetBool(optionNameChequebookEnable), CORSAllowedOrigins: c.config.GetStringSlice(optionCORSAllowedOrigins), @@ -297,12 +301,15 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo DBWriteBufferSize: c.config.GetUint64(optionNameDBWriteBufferSize), EnableStorageIncentives: c.config.GetBool(optionNameStorageIncentivesEnable), EnableWS: c.config.GetBool(optionNameP2PWSEnable), + AutoTLSDomain: c.config.GetString(optionAutoTLSDomain), + AutoTLSRegistrationEndpoint: c.config.GetString(optionAutoTLSRegistrationEndpoint), FullNodeMode: fullNode, Logger: logger, MinimumGasTipCap: c.config.GetUint64(optionNameMinimumGasTipCap), MinimumStorageRadius: c.config.GetUint(optionMinimumStorageRadius), MutexProfile: c.config.GetBool(optionNamePProfMutex), NATAddr: c.config.GetString(optionNameNATAddr), + NATWSSAddr: c.config.GetString(optionNATWSSAddr), NeighborhoodSuggester: neighborhoodSuggester, PaymentEarly: c.config.GetInt64(optionNamePaymentEarly), PaymentThreshold: c.config.GetString(optionNamePaymentThreshold), diff --git a/go.mod b/go.mod index a55a0923d50..1cee528864c 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( contrib.go.opencensus.io/exporter/prometheus v0.4.2 github.com/armon/go-radix v1.0.0 github.com/btcsuite/btcd/btcec/v2 v2.3.2 + github.com/caddyserver/certmagic v0.21.6 github.com/coreos/go-semver v0.3.0 github.com/ethereum/go-ethereum v1.15.11 github.com/ethersphere/batch-archive v0.0.4 @@ -15,33 +16,33 @@ require ( github.com/ethersphere/go-storage-incentives-abi v0.9.4 github.com/ethersphere/go-sw3-abi v0.6.9 github.com/ethersphere/langos v1.0.0 - github.com/go-playground/validator/v10 v10.11.1 + github.com/go-playground/validator/v10 v10.19.0 github.com/gogo/protobuf v1.3.2 - github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.4.0 + github.com/google/go-cmp v0.7.0 + github.com/google/uuid v1.6.0 github.com/gorilla/handlers v1.4.2 - github.com/gorilla/mux v1.8.0 - github.com/gorilla/websocket v1.5.1 + github.com/gorilla/mux v1.8.1 + github.com/gorilla/websocket v1.5.3 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/golang-lru/v2 v2.0.5 - github.com/ipfs/go-cid v0.4.1 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/ipfs/go-cid v0.5.0 + github.com/ipshipyard/p2p-forge v0.7.0 github.com/kardianos/service v1.2.2 github.com/klauspost/reedsolomon v1.11.8 - github.com/libp2p/go-libp2p v0.33.2 - github.com/multiformats/go-multiaddr v0.12.3 - github.com/multiformats/go-multiaddr-dns v0.3.1 + github.com/libp2p/go-libp2p v0.46.0 + github.com/multiformats/go-multiaddr v0.16.1 + github.com/multiformats/go-multiaddr-dns v0.4.1 github.com/multiformats/go-multihash v0.2.3 - github.com/multiformats/go-multistream v0.5.0 - github.com/multiformats/go-varint v0.0.7 + github.com/multiformats/go-multistream v0.6.1 github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/spf13/afero v1.6.0 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.7.0 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/uber/jaeger-client-go v2.24.0+incompatible - github.com/vmihailenco/msgpack/v5 v5.3.4 + github.com/vmihailenco/msgpack/v5 v5.4.1 github.com/wealdtech/go-ens/v3 v3.5.1 gitlab.com/nolash/go-mockbytes v0.0.7 go.uber.org/atomic v1.11.0 @@ -51,7 +52,7 @@ require ( golang.org/x/sync v0.18.0 golang.org/x/sys v0.38.0 golang.org/x/term v0.37.0 - golang.org/x/time v0.9.0 + golang.org/x/time v0.12.0 gopkg.in/yaml.v2 v2.4.0 resenje.org/feed v0.1.2 resenje.org/multex v0.1.0 @@ -59,71 +60,62 @@ require ( resenje.org/web v0.4.3 ) -require golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect - require ( - github.com/BurntSushi/toml v1.1.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/codahale/hdrhistogram v0.0.0-00010101000000-000000000000 // indirect github.com/consensys/gnark-crypto v0.18.1 // indirect - github.com/containerd/cgroups v1.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/elastic/gosigar v0.14.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/felixge/fgprof v0.9.5 github.com/flynn/noise v1.1.0 // indirect - github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect - github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipfs/go-log/v2 v2.6.0 // 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.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/koron/go-ssdp v0.0.6 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/libdns/libdns v0.2.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.2.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-netroute v0.3.0 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/libp2p/go-yamux/v5 v5.0.1 // indirect github.com/magiconair/properties v1.8.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.58 // indirect + github.com/mholt/acmez/v3 v3.0.0 // indirect + github.com/miekg/dns v1.1.66 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -133,24 +125,42 @@ require ( github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multicodec v0.9.1 // indirect + github.com/multiformats/go-varint v0.0.7 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // indirect - github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/onsi/gomega v1.36.3 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pelletier/go-toml v1.8.0 // indirect + github.com/pion/datachannel v1.5.10 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/ice/v4 v4.0.10 // indirect + github.com/pion/interceptor v0.1.40 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.19 // indirect + github.com/pion/sctp v1.8.39 // indirect + github.com/pion/sdp/v3 v3.0.13 // indirect + github.com/pion/srtp/v3 v3.0.6 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect + github.com/pion/turn/v4 v4.0.2 // indirect + github.com/pion/webrtc/v4 v4.1.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.6.1 // indirect - github.com/prometheus/common v0.62.0 - github.com/prometheus/procfs v0.15.1 // indirect - github.com/prometheus/statsd_exporter v0.22.7 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.42.0 // indirect - github.com/quic-go/webtransport-go v0.6.0 // indirect - github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.64.0 + github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/statsd_exporter v0.26.1 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/quic-go/quic-go v0.57.1 // indirect + github.com/quic-go/webtransport-go v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/shirou/gopsutil v3.21.5+incompatible // indirect - github.com/smartystreets/assertions v1.1.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/cast v1.3.0 // indirect github.com/spf13/jwalterweatherman v1.0.0 // indirect @@ -162,20 +172,24 @@ require ( github.com/uber/jaeger-lib v2.2.0+incompatible // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/wealdtech/go-multicodec v1.4.0 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.20.1 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/dig v1.19.0 // indirect + go.uber.org/fx v1.24.0 // indirect + go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + go.uber.org/zap v1.27.0 + go.uber.org/zap/exp v0.3.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect golang.org/x/mod v0.29.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect golang.org/x/text v0.31.0 // indirect golang.org/x/tools v0.38.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/ini.v1 v1.57.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.4.1 // indirect ) replace github.com/codahale/hdrhistogram => github.com/HdrHistogram/hdrhistogram-go v0.0.0-20200919145931-8dac23c8dac1 diff --git a/go.sum b/go.sum index 3541cb2be1c..7b0f87f302a 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= @@ -105,8 +105,6 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -138,6 +136,10 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/caddyserver/certmagic v0.21.6 h1:1th6GfprVfsAtFNOu4StNMF5IxK5XiaI0yZhAHlZFPE= +github.com/caddyserver/certmagic v0.21.6/go.mod h1:n1sCo7zV1Ez2j+89wrzDxo4N/T1Ws/Vx8u5NvuBFabw= +github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= +github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= @@ -158,7 +160,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -178,21 +179,14 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= -github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -206,18 +200,19 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.6.0 h1:w/d1ntwh91XI0b/8ja7+u5SvA4IFfM0UNNLmiDR1gg0= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= @@ -226,16 +221,10 @@ github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMa github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -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= @@ -267,12 +256,13 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= @@ -295,34 +285,27 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -366,8 +349,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw 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.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -384,21 +365,18 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.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= @@ -408,28 +386,27 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf 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-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18= +github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= 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.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= @@ -440,8 +417,9 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -459,8 +437,8 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA 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 v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -499,10 +477,12 @@ github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bS github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -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-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg= +github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8= +github.com/ipshipyard/p2p-forge v0.7.0 h1:PQayexxZC1FR2Vx0XOSbmZ6wDPliidS48I+xXWuF+YU= +github.com/ipshipyard/p2p-forge v0.7.0/go.mod h1:i2wg0p7WmHGyo5vYaK9COZBp8BN5Drncfu3WoQNZlQY= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -526,7 +506,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm 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/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= -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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -543,26 +522,25 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY= github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A= 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/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= +github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -576,15 +554,17 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= 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-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.33.2 h1:vCdwnFxoGOXMKmaGHlDSnL4bM3fQeW8pgIa9DECnb40= -github.com/libp2p/go-libp2p v0.33.2/go.mod h1:zTeppLuCvUIkT118pFVzA8xzP/p2dJYOMApCkFh0Yww= +github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= +github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +github.com/libp2p/go-libp2p v0.46.0 h1:0T2yvIKpZ3DVYCuPOFxPD1layhRU486pj9rSlGWYnDM= +github.com/libp2p/go-libp2p v0.46.0/go.mod h1:TbIDnpDjBLa7isdgYpbxozIVPBTmM/7qKOJP4SFySrQ= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -592,20 +572,20 @@ github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= -github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc= +github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-yamux/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg= +github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lucas-clemente/quic-go v0.15.2/go.mod h1:qxmO5Y4ZMhdNkunGfxuZnZXnJwYpW9vjQkyrZ7BsgUI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= +github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= github.com/marten-seemann/qtls v0.8.0/go.mod h1:Lao6jDqlCfxyLKYFmZXGm2LSHBgVn+P+ROOex6YkT+k= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= @@ -623,7 +603,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -633,11 +612,12 @@ github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mholt/acmez/v3 v3.0.0 h1:r1NcjuWR0VaKP2BTjDK9LRFBw/WvURx3jlaEUl9Ht8E= +github.com/mholt/acmez/v3 v3.0.0/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= 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= @@ -678,29 +658,27 @@ github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoR github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= github.com/multiformats/go-multiaddr v0.3.2/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr v0.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8= -github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw= +github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= +github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= 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.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= 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.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= -github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= @@ -722,20 +700,16 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +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/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 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.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= +github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -756,26 +730,59 @@ github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg= github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pion/dtls/v2 v2.2.8 h1:BUroldfiIbV9jSnC6cKOMnyiORRWrWWpV11JUyEu5OA= -github.com/pion/dtls/v2 v2.2.8/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= +github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= +github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4= +github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.19 h1:jhdO/3XhL/aKm/wARFVmvTfq0lC/CvN1xwYKmduly3c= +github.com/pion/rtp v1.8.19/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= +github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.13 h1:uN3SS2b+QDZnWXgdr69SM8KB4EbcnPnPf2Laxhty/l4= +github.com/pion/sdp/v3 v3.0.13/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4= +github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= -github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo= +github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps= +github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= +github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= +github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 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= @@ -787,14 +794,14 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -806,8 +813,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -818,20 +825,19 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= +github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w= +github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= -github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= -github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= -github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= -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/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10= +github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= +github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= +github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -839,10 +845,8 @@ github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRr github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= @@ -884,11 +888,7 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k 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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck= -github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= @@ -927,8 +927,10 @@ 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -956,15 +958,13 @@ github.com/uber/jaeger-client-go v2.24.0+incompatible h1:CGchgJcHsDd2jWnaL4XngBy github.com/uber/jaeger-client-go v2.24.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= 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/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= -github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/wealdtech/go-ens/v3 v3.5.1 h1:0VqkCjIGfIVdwHIf2QqYWWt3bbR1UE7RwBGx7YPpufQ= @@ -974,6 +974,9 @@ github.com/wealdtech/go-multicodec v1.4.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3h github.com/wealdtech/go-string2eth v1.1.0 h1:USJQmysUrBYYmZs7d45pMb90hRSyEwizP7lZaOZLDAw= github.com/wealdtech/go-string2eth v1.1.0/go.mod h1:RUzsLjJtbZaJ/3UKn9kY19a/vCCUHtEWoUW3uiK6yGU= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= @@ -982,7 +985,13 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= +github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= +github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/nolash/go-mockbytes v0.0.7 h1:9XVFpEfY67kGBVJve3uV19kzqORdlo7V+q09OE6Yo54= gitlab.com/nolash/go-mockbytes v0.0.7/go.mod h1:KKOpNTT39j2Eo+P6uUTOncntfeKY6AFh/2CxuD5MpgE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -997,27 +1006,25 @@ 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.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= -go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= -go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= +go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= 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-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1042,7 +1049,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh 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.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1058,8 +1068,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1083,6 +1093,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1131,12 +1143,16 @@ 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-20210220033124-5f55cee0dc0d/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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1161,9 +1177,10 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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= @@ -1198,7 +1215,6 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200107162124-548cf772de50/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= @@ -1220,30 +1236,27 @@ golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-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-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= @@ -1251,6 +1264,11 @@ golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJ 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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1261,6 +1279,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1268,8 +1290,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1322,7 +1344,8 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1427,8 +1450,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1440,8 +1463,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= @@ -1476,8 +1499,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= resenje.org/daemon v0.1.2/go.mod h1:mF5JRpH3EbrxI9WoeKY78e6PqSsbBtX9jAQL5vj/GBA= resenje.org/email v0.1.3/go.mod h1:OhAVLRG3vqd9NSgayN3pAgzxTmc2B6mAefgShZvEgf0= resenje.org/feed v0.1.2 h1:3OianQkoI4EalWx1SlzHtGjUMsoB4XTJQbeehWiyeFI= diff --git a/packaging/bee.yaml b/packaging/bee.yaml index 42ee156d0de..41a6b2a2568 100644 --- a/packaging/bee.yaml +++ b/packaging/bee.yaml @@ -120,3 +120,15 @@ password-file: "/var/lib/bee/password" # welcome-message: "" ## withdrawal target addresses # withdrawal-addresses-whitelist: [] +## enable wss p2p connections (default: false) +# p2p-wss-enable: false +## wss address (default: :1635) +# p2p-wss-addr: :1635 +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain (default: libp2p.direct) +# autotls-domain: "" +## autotls registration endpoint (default: https://registration.libp2p.direct) +# autotls-registration-endpoint: "" +## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) +# autotls-ca-endpoint: "" diff --git a/packaging/homebrew-amd64/bee.yaml b/packaging/homebrew-amd64/bee.yaml index 14a32f70116..4e93b8e3bab 100644 --- a/packaging/homebrew-amd64/bee.yaml +++ b/packaging/homebrew-amd64/bee.yaml @@ -120,3 +120,15 @@ password-file: "/usr/local/var/lib/swarm-bee/password" # welcome-message: "" ## withdrawal target addresses # withdrawal-addresses-whitelist: [] +## enable wss p2p connections (default: false) +# p2p-wss-enable: false +## wss address (default: :1635) +# p2p-wss-addr: :1635 +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain (default: libp2p.direct) +# autotls-domain: "" +## autotls registration endpoint (default: https://registration.libp2p.direct) +# autotls-registration-endpoint: "" +## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) +# autotls-ca-endpoint: "" diff --git a/packaging/homebrew-arm64/bee.yaml b/packaging/homebrew-arm64/bee.yaml index 55d522b601c..291288c3eed 100644 --- a/packaging/homebrew-arm64/bee.yaml +++ b/packaging/homebrew-arm64/bee.yaml @@ -120,3 +120,15 @@ password-file: "/opt/homebrew/var/lib/swarm-bee/password" # welcome-message: "" ## withdrawal target addresses # withdrawal-addresses-whitelist: [] +## enable wss p2p connections (default: false) +# p2p-wss-enable: false +## wss address (default: :1635) +# p2p-wss-addr: :1635 +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain (default: libp2p.direct) +# autotls-domain: "" +## autotls registration endpoint (default: https://registration.libp2p.direct) +# autotls-registration-endpoint: "" +## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) +# autotls-ca-endpoint: "" diff --git a/packaging/scoop/bee.yaml b/packaging/scoop/bee.yaml index 70bed38f947..d73c9f4feb1 100644 --- a/packaging/scoop/bee.yaml +++ b/packaging/scoop/bee.yaml @@ -120,3 +120,15 @@ password-file: "./password" # welcome-message: "" ## withdrawal target addresses # withdrawal-addresses-whitelist: [] +## enable wss p2p connections (default: false) +# p2p-wss-enable: false +## wss address (default: :1635) +# p2p-wss-addr: :1635 +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain (default: libp2p.direct) +# autotls-domain: "" +## autotls registration endpoint (default: https://registration.libp2p.direct) +# autotls-registration-endpoint: "" +## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) +# autotls-ca-endpoint: "" diff --git a/pkg/api/peer_test.go b/pkg/api/peer_test.go index 15694632709..1175e7d6bc4 100644 --- a/pkg/api/peer_test.go +++ b/pkg/api/peer_test.go @@ -62,7 +62,6 @@ func TestConnect(t *testing.T) { }) t.Run("ok", func(t *testing.T) { - t.Parallel() jsonhttptest.Request(t, testServer, http.MethodPost, "/connect"+underlay, http.StatusOK, jsonhttptest.WithExpectedJSONResponse(api.PeerConnectResponse{ Address: overlay.String(), @@ -71,7 +70,6 @@ func TestConnect(t *testing.T) { }) t.Run("error", func(t *testing.T) { - t.Parallel() jsonhttptest.Request(t, testServer, http.MethodPost, "/connect"+errorUnderlay, http.StatusInternalServerError, jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ Code: http.StatusInternalServerError, @@ -81,7 +79,6 @@ func TestConnect(t *testing.T) { }) t.Run("error - add peer", func(t *testing.T) { - t.Parallel() testServer, _, _, _ := newTestServer(t, testServerOptions{ P2P: mock.New(mock.WithConnectFunc(func(ctx context.Context, addrs []ma.Multiaddr) (*bzz.Address, error) { for _, addr := range addrs { diff --git a/pkg/api/util.go b/pkg/api/util.go index 60780c5acb4..d8911f4ecf4 100644 --- a/pkg/api/util.go +++ b/pkg/api/util.go @@ -210,14 +210,23 @@ func mapStructure(input, output any, hooks map[string]func(v string) (string, er case reflect.String: field.SetString(value) case reflect.Slice: - if value == "" { - return nil // Nil slice. - } - val, err := hex.DecodeString(value) - if err != nil { - return err + switch field.Type() { + case reflect.TypeFor[multiaddr.Multiaddr](): + val, err := multiaddr.NewMultiaddr(value) + if err != nil { + return err + } + field.Set(reflect.ValueOf(val)) + default: + if value == "" { + return nil // Nil slice. + } + val, err := hex.DecodeString(value) + if err != nil { + return err + } + field.SetBytes(val) } - field.SetBytes(val) case reflect.Array: switch field.Interface().(type) { case common.Hash: @@ -251,15 +260,6 @@ func mapStructure(input, output any, hooks map[string]func(v string) (string, er } field.Set(reflect.ValueOf(*val)) } - case reflect.Interface: - switch field.Type() { - case reflect.TypeFor[multiaddr.Multiaddr](): - val, err := multiaddr.NewMultiaddr(value) - if err != nil { - return err - } - field.Set(reflect.ValueOf(val)) - } default: return fmt.Errorf("unsupported type %T", field.Interface()) } diff --git a/pkg/api/util_test.go b/pkg/api/util_test.go index d9ae6732810..b35280de4bd 100644 --- a/pkg/api/util_test.go +++ b/pkg/api/util_test.go @@ -17,6 +17,7 @@ import ( "github.com/ethersphere/bee/v2/pkg/api" "github.com/ethersphere/bee/v2/pkg/swarm" "github.com/google/go-cmp/cmp" + "github.com/multiformats/go-multiaddr" ) type ( @@ -95,11 +96,20 @@ type ( mapSwarmAddressTest struct { SwarmAddressVal swarm.Address `map:"swarmAddressVal"` } + + mapMultiaddrTest struct { + MultiaddrVal multiaddr.Multiaddr `map:"multiaddrVal"` + } ) func TestMapStructure(t *testing.T) { t.Parallel() + validMultiaddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/8080") + if err != nil { + t.Fatal(err) + } + tests := []struct { name string src any @@ -497,6 +507,10 @@ func TestMapStructure(t *testing.T) { name: "swarm.Address value", src: map[string]string{"swarmAddressVal": "1234567890abcdef"}, want: &mapSwarmAddressTest{SwarmAddressVal: swarm.MustParseHexAddress("1234567890abcdef")}, + }, { + name: "multiaddr.Multiaddr value", + src: map[string]string{"multiaddrVal": "/ip4/127.0.0.1/tcp/8080"}, + want: &mapMultiaddrTest{MultiaddrVal: validMultiaddr}, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/bzz/underlay_test.go b/pkg/bzz/underlay_test.go index f6e4fc7933b..5bc4e34c19d 100644 --- a/pkg/bzz/underlay_test.go +++ b/pkg/bzz/underlay_test.go @@ -106,6 +106,35 @@ func TestDeserializeUnderlays(t *testing.T) { } }) + t.Run("serialize deserialize empty list", func(t *testing.T) { + addrs := []multiaddr.Multiaddr{} + serialized := bzz.SerializeUnderlays(addrs) + if !bytes.Equal(serialized, []byte{bzz.UnderlayListPrefix}) { + t.Errorf("expected %v, got %v", []byte{bzz.UnderlayListPrefix}, serialized) + } + deserialized, err := bzz.DeserializeUnderlays(serialized) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(deserialized) != 0 { + t.Errorf("expected empty slice, got %v", deserialized) + } + }) + + t.Run("serialize deserialize nil list", func(t *testing.T) { + serialized := bzz.SerializeUnderlays(nil) + if !bytes.Equal(serialized, []byte{bzz.UnderlayListPrefix}) { + t.Errorf("expected %v, got %v", []byte{bzz.UnderlayListPrefix}, serialized) + } + deserialized, err := bzz.DeserializeUnderlays(serialized) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(deserialized) != 0 { + t.Errorf("expected empty slice, got %v", deserialized) + } + }) + t.Run("corrupted list - length too long", func(t *testing.T) { maBytes := ip4TCPAddr.Bytes() var buf bytes.Buffer diff --git a/pkg/hive/hive.go b/pkg/hive/hive.go index f5fe1b3bf53..1f49fe2808c 100644 --- a/pkg/hive/hive.go +++ b/pkg/hive/hive.go @@ -12,7 +12,6 @@ package hive import ( "context" - "encoding/hex" "errors" "fmt" "sync" @@ -36,13 +35,11 @@ import ( const loggerName = "hive" const ( - protocolName = "hive" - protocolVersion = "1.1.0" - peersStreamName = "peers" - messageTimeout = 1 * time.Minute // maximum allowed time for a message to be read or written. - maxBatchSize = 30 - pingTimeout = time.Second * 15 // time to wait for ping to succeed - batchValidationTimeout = 5 * time.Minute // prevent lock contention on peer validation + protocolName = "hive" + protocolVersion = "1.1.0" + peersStreamName = "peers" + messageTimeout = 1 * time.Minute // maximum allowed time for a message to be read or written. + maxBatchSize = 30 ) var ( @@ -53,7 +50,7 @@ var ( ) type Service struct { - streamer p2p.StreamerPinger + streamer p2p.Streamer addressBook addressbook.GetPutter addPeersHandler func(...swarm.Address) networkID uint64 @@ -67,9 +64,10 @@ type Service struct { sem *semaphore.Weighted bootnode bool allowPrivateCIDRs bool + overlay swarm.Address } -func New(streamer p2p.StreamerPinger, addressbook addressbook.GetPutter, networkID uint64, bootnode bool, allowPrivateCIDRs bool, logger log.Logger) *Service { +func New(streamer p2p.Streamer, addressbook addressbook.GetPutter, networkID uint64, bootnode bool, allowPrivateCIDRs bool, overlay swarm.Address, logger log.Logger) *Service { svc := &Service{ streamer: streamer, logger: logger.WithName(loggerName).Register(), @@ -83,6 +81,7 @@ func New(streamer p2p.StreamerPinger, addressbook addressbook.GetPutter, network sem: semaphore.NewWeighted(int64(swarm.MaxBins)), bootnode: bootnode, allowPrivateCIDRs: allowPrivateCIDRs, + overlay: overlay, } if !bootnode { @@ -177,6 +176,11 @@ func (s *Service) sendPeers(ctx context.Context, peer swarm.Address, peers []swa w, _ := protobuf.NewWriterAndReader(stream) var peersRequest pb.Peers for _, p := range peers { + if p.Equal(s.overlay) { + s.logger.Debug("skipping self-address in broadcast", "overlay", p.String()) + continue + } + addr, err := s.addressBook.Get(p) if err != nil { if errors.Is(err, addressbook.ErrNotFound) { @@ -263,83 +267,15 @@ func (s *Service) startCheckPeersHandler() { return case newPeers := <-s.peersChan: s.wg.Go(func() { - cctx, cancel := context.WithTimeout(ctx, batchValidationTimeout) - defer cancel() - s.checkAndAddPeers(cctx, newPeers) + s.checkAndAddPeers(newPeers) }) } } }) } -func (s *Service) checkAndAddPeers(ctx context.Context, peers pb.Peers) { - var peersToAdd []swarm.Address - mtx := sync.Mutex{} - wg := sync.WaitGroup{} - - addPeer := func(newPeer *pb.BzzAddress, multiUnderlay []ma.Multiaddr) { - err := s.sem.Acquire(ctx, 1) - if err != nil { - return - } - - wg.Add(1) - go func() { - s.metrics.PeerConnectAttempts.Inc() - - defer func() { - s.sem.Release(1) - wg.Done() - }() - - ctx, cancel := context.WithTimeout(ctx, pingTimeout) - defer cancel() - - var ( - pingSuccessful bool - start time.Time - ) - for _, underlay := range multiUnderlay { - // ping each underlay address, pick first available - start = time.Now() - if _, err := s.streamer.Ping(ctx, underlay); err != nil { - s.logger.Debug("unreachable peer underlay", "peer_address", hex.EncodeToString(newPeer.Overlay), "underlay", underlay, "error", err) - continue - } - pingSuccessful = true - s.logger.Debug("reachable peer underlay", "peer_address", hex.EncodeToString(newPeer.Overlay), "underlay", underlay) - break - } - - if !pingSuccessful { - // none of underlay addresses is available - s.metrics.PingFailureTime.Observe(time.Since(start).Seconds()) - s.metrics.UnreachablePeers.Inc() - return - } - - s.metrics.PingTime.Observe(time.Since(start).Seconds()) - s.metrics.ReachablePeers.Inc() - - bzzAddress := bzz.Address{ - Overlay: swarm.NewAddress(newPeer.Overlay), - Underlays: multiUnderlay, - Signature: newPeer.Signature, - Nonce: newPeer.Nonce, - } - - err := s.addressBook.Put(bzzAddress.Overlay, bzzAddress) - if err != nil { - s.metrics.StorePeerErr.Inc() - s.logger.Warning("skipping peer in response", "peer_address", newPeer.String(), "error", err) - return - } - - mtx.Lock() - peersToAdd = append(peersToAdd, bzzAddress.Overlay) - mtx.Unlock() - }() - } +func (s *Service) checkAndAddPeers(peers pb.Peers) { + peersToAdd := make([]swarm.Address, 0, len(peers.Peers)) for _, p := range peers.Peers { multiUnderlays, err := bzz.DeserializeUnderlays(p.Underlay) @@ -361,10 +297,28 @@ func (s *Service) checkAndAddPeers(ctx context.Context, peers pb.Peers) { continue } - // add peer does not exist in the addressbook - addPeer(p, multiUnderlays) + overlayAddr := swarm.NewAddress(p.Overlay) + + if overlayAddr.Equal(s.overlay) { + s.logger.Debug("skipping self-address in peer list", "overlay", overlayAddr.String()) + continue + } + + bzzAddress := bzz.Address{ + Overlay: overlayAddr, + Underlays: multiUnderlays, + Signature: p.Signature, + Nonce: p.Nonce, + } + + if err := s.addressBook.Put(bzzAddress.Overlay, bzzAddress); err != nil { + s.metrics.StorePeerErr.Inc() + s.logger.Warning("put peer in addressbook", "peer_address", p.String(), "error", err) + continue + } + + peersToAdd = append(peersToAdd, bzzAddress.Overlay) } - wg.Wait() if s.addPeersHandler != nil && len(peersToAdd) > 0 { s.addPeersHandler(peersToAdd...) diff --git a/pkg/hive/hive_test.go b/pkg/hive/hive_test.go index 1f0d6eecd53..ec603c8bb2b 100644 --- a/pkg/hive/hive_test.go +++ b/pkg/hive/hive_test.go @@ -8,7 +8,6 @@ import ( "bytes" "context" "encoding/hex" - "errors" "fmt" "strconv" "testing" @@ -48,13 +47,12 @@ func TestHandlerRateLimit(t *testing.T) { addressbookclean := ab.New(mock.NewStateStore()) - // new recorder for handling Ping + // new recorder streamer := streamtest.New() // create a hive server that handles the incoming stream - server := hive.New(streamer, addressbookclean, networkID, false, true, logger) - testutil.CleanupCloser(t, server) - serverAddress := swarm.RandAddress(t) + server := hive.New(streamer, addressbookclean, networkID, false, true, serverAddress, logger) + testutil.CleanupCloser(t, server) // setup the stream recorder to record stream data serverRecorder := streamtest.New( @@ -95,7 +93,8 @@ func TestHandlerRateLimit(t *testing.T) { } // create a hive client that will do broadcast - client := hive.New(serverRecorder, addressbook, networkID, false, true, logger) + clientAddress := swarm.RandAddress(t) + client := hive.New(serverRecorder, addressbook, networkID, false, true, clientAddress, logger) err := client.BroadcastPeers(context.Background(), serverAddress, peers...) if err != nil { t.Fatal(err) @@ -192,7 +191,6 @@ func TestBroadcastPeers(t *testing.T) { wantOverlays []swarm.Address wantBzzAddresses []bzz.Address allowPrivateCIDRs bool - pingErr func(addr ma.Multiaddr) (time.Duration, error) }{ "OK - single record": { addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"), @@ -234,24 +232,6 @@ func TestBroadcastPeers(t *testing.T) { wantBzzAddresses: bzzAddresses[:2*hive.MaxBatchSize], allowPrivateCIDRs: true, }, - "OK - single batch - skip ping failures": { - addresee: swarm.MustParseHexAddress("ca1e9f3938cc1425c6061b96ad9eb93e134dfe8734ad490164ef20af9d1cf59c"), - peers: overlays[:15], - wantMsgs: []pb.Peers{{Peers: wantMsgs[0].Peers[:15]}}, - wantOverlays: overlays[:10], - wantBzzAddresses: bzzAddresses[:10], - allowPrivateCIDRs: true, - pingErr: func(addr ma.Multiaddr) (rtt time.Duration, err error) { - for _, v := range bzzAddresses[10:15] { - for _, underlay := range v.Underlays { - if underlay.Equal(addr) { - return rtt, errors.New("ping failure") - } - } - } - return rtt, nil - }, - }, "Ok - don't advertise private CIDRs only": { addresee: overlays[len(overlays)-1], peers: overlays[:15], @@ -291,15 +271,10 @@ func TestBroadcastPeers(t *testing.T) { addressbookclean := ab.New(mock.NewStateStore()) - // new recorder for handling Ping - var streamer *streamtest.Recorder - if tc.pingErr != nil { - streamer = streamtest.New(streamtest.WithPingErr(tc.pingErr)) - } else { - streamer = streamtest.New() - } + streamer := streamtest.New() // create a hive server that handles the incoming stream - server := hive.New(streamer, addressbookclean, networkID, false, true, logger) + serverAddress := swarm.RandAddress(t) + server := hive.New(streamer, addressbookclean, networkID, false, true, serverAddress, logger) testutil.CleanupCloser(t, server) // setup the stream recorder to record stream data @@ -308,7 +283,8 @@ func TestBroadcastPeers(t *testing.T) { ) // create a hive client that will do broadcast - client := hive.New(recorder, addressbook, networkID, false, tc.allowPrivateCIDRs, logger) + clientAddress := swarm.RandAddress(t) + client := hive.New(recorder, addressbook, networkID, false, tc.allowPrivateCIDRs, clientAddress, logger) if err := client.BroadcastPeers(context.Background(), tc.addresee, tc.peers...); err != nil { t.Fatal(err) @@ -470,3 +446,222 @@ func shortHex(b []byte) string { } return s } + +// TestBroadcastPeersSkipsSelf verifies that hive does not broadcast self address +// to other peers, preventing self-connection attempts. +func TestBroadcastPeersSkipsSelf(t *testing.T) { + t.Parallel() + + logger := log.Noop + statestore := mock.NewStateStore() + addressbook := ab.New(statestore) + networkID := uint64(1) + addressbookclean := ab.New(mock.NewStateStore()) + + // Create addresses + serverAddress := swarm.RandAddress(t) + clientAddress := swarm.RandAddress(t) + + // Create a peer address + peer1 := swarm.RandAddress(t) + underlay1, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1234") + if err != nil { + t.Fatal(err) + } + pk, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + signer := crypto.NewDefaultSigner(pk) + overlay1, err := crypto.NewOverlayAddress(pk.PublicKey, networkID, block) + if err != nil { + t.Fatal(err) + } + bzzAddr1, err := bzz.NewAddress(signer, []ma.Multiaddr{underlay1}, overlay1, networkID, nonce) + if err != nil { + t.Fatal(err) + } + if err := addressbook.Put(bzzAddr1.Overlay, *bzzAddr1); err != nil { + t.Fatal(err) + } + + // Create self address entry in addressbook + underlayClient, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/9999") + if err != nil { + t.Fatal(err) + } + pkClient, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + signerClient := crypto.NewDefaultSigner(pkClient) + bzzAddrClient, err := bzz.NewAddress(signerClient, []ma.Multiaddr{underlayClient}, clientAddress, networkID, nonce) + if err != nil { + t.Fatal(err) + } + if err := addressbook.Put(clientAddress, *bzzAddrClient); err != nil { + t.Fatal(err) + } + + // Setup server + streamer := streamtest.New() + server := hive.New(streamer, addressbookclean, networkID, false, true, serverAddress, logger) + testutil.CleanupCloser(t, server) + + serverRecorder := streamtest.New( + streamtest.WithProtocols(server.Protocol()), + ) + + // Setup client + client := hive.New(serverRecorder, addressbook, networkID, false, true, clientAddress, logger) + testutil.CleanupCloser(t, client) + + // Try to broadcast: peer1, clientAddress (self), and another peer + peersIncludingSelf := []swarm.Address{bzzAddr1.Overlay, clientAddress, peer1} + + err = client.BroadcastPeers(context.Background(), serverAddress, peersIncludingSelf...) + if err != nil { + t.Fatal(err) + } + + // Get records + records, err := serverRecorder.Records(serverAddress, "hive", "1.1.0", "peers") + if err != nil { + t.Fatal(err) + } + + if len(records) == 0 { + t.Fatal("expected at least one record") + } + + // Read the messages + messages, err := readAndAssertPeersMsgs(records[0].In(), 1) + if err != nil { + t.Fatal(err) + } + + // Verify that clientAddress (self) was NOT included in broadcast + for _, peerMsg := range messages[0].Peers { + receivedOverlay := swarm.NewAddress(peerMsg.Overlay) + if receivedOverlay.Equal(clientAddress) { + t.Fatal("self address should not be broadcast to peers") + } + } + + // Verify server addressbook eventually contains only the valid peers, not self + err = spinlock.Wait(spinTimeout, func() bool { + overlays, err := addressbookclean.Overlays() + if err != nil { + t.Fatal(err) + } + // Should only have bzzAddr1, not clientAddress + for _, o := range overlays { + if o.Equal(clientAddress) { + return false // self should not be in addressbook + } + } + return true + }) + if err != nil { + t.Fatal("self address found in server addressbook") + } +} + +// TestReceivePeersSkipsSelf verifies that hive does not add self address +// when receiving peer lists from other peers. +func TestReceivePeersSkipsSelf(t *testing.T) { + t.Parallel() + + logger := log.Noop + statestore := mock.NewStateStore() + addressbook := ab.New(statestore) + networkID := uint64(1) + addressbookclean := ab.New(mock.NewStateStore()) + + // Create addresses + serverAddress := swarm.RandAddress(t) + clientAddress := swarm.RandAddress(t) + + // Create a valid peer + underlay1, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1234") + if err != nil { + t.Fatal(err) + } + pk1, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + signer1 := crypto.NewDefaultSigner(pk1) + overlay1, err := crypto.NewOverlayAddress(pk1.PublicKey, networkID, block) + if err != nil { + t.Fatal(err) + } + bzzAddr1, err := bzz.NewAddress(signer1, []ma.Multiaddr{underlay1}, overlay1, networkID, nonce) + if err != nil { + t.Fatal(err) + } + if err := addressbook.Put(bzzAddr1.Overlay, *bzzAddr1); err != nil { + t.Fatal(err) + } + + // Create self address entry (serverAddress) that will be sent by client + underlayServer, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/8888") + if err != nil { + t.Fatal(err) + } + pkServer, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + signerServer := crypto.NewDefaultSigner(pkServer) + bzzAddrServer, err := bzz.NewAddress(signerServer, []ma.Multiaddr{underlayServer}, serverAddress, networkID, nonce) + if err != nil { + t.Fatal(err) + } + // Add server's own address to client's addressbook (so client can send it) + if err := addressbook.Put(serverAddress, *bzzAddrServer); err != nil { + t.Fatal(err) + } + + // Setup server that will receive peers including its own address + streamer := streamtest.New() + server := hive.New(streamer, addressbookclean, networkID, false, true, serverAddress, logger) + testutil.CleanupCloser(t, server) + + serverRecorder := streamtest.New( + streamtest.WithProtocols(server.Protocol()), + ) + + // Setup client + client := hive.New(serverRecorder, addressbook, networkID, false, true, clientAddress, logger) + testutil.CleanupCloser(t, client) + + // Client broadcasts: valid peer and server's own address + peersIncludingSelf := []swarm.Address{bzzAddr1.Overlay, serverAddress} + + err = client.BroadcastPeers(context.Background(), serverAddress, peersIncludingSelf...) + if err != nil { + t.Fatal(err) + } + + // Wait a bit for server to process + time.Sleep(100 * time.Millisecond) + + // Verify server's addressbook does NOT contain its own address + overlays, err := addressbookclean.Overlays() + if err != nil { + t.Fatal(err) + } + + for _, o := range overlays { + if o.Equal(serverAddress) { + t.Fatal("server should not add its own address to addressbook when received from peer") + } + } + + // Verify server does have the valid peer + _, err = addressbookclean.Get(bzzAddr1.Overlay) + if err != nil { + t.Fatalf("expected server to have valid peer in addressbook, got error: %v", err) + } +} diff --git a/pkg/node/bootstrap.go b/pkg/node/bootstrap.go index 047c306aaf2..eab32166ec9 100644 --- a/pkg/node/bootstrap.go +++ b/pkg/node/bootstrap.go @@ -97,12 +97,19 @@ func bootstrapNode( }() p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{ - PrivateKey: libp2pPrivateKey, - NATAddr: o.NATAddr, - EnableWS: o.EnableWS, - WelcomeMessage: o.WelcomeMessage, - FullNode: false, - Nonce: nonce, + PrivateKey: libp2pPrivateKey, + NATAddr: o.NATAddr, + NATWSSAddr: o.NATWSSAddr, + EnableWS: o.EnableWS, + EnableWSS: o.EnableWSS, + WSSAddr: o.WSSAddr, + AutoTLSStorageDir: o.AutoTLSStorageDir, + AutoTLSDomain: o.AutoTLSDomain, + AutoTLSRegistrationEndpoint: o.AutoTLSRegistrationEndpoint, + AutoTLSCAEndpoint: o.AutoTLSCAEndpoint, + WelcomeMessage: o.WelcomeMessage, + FullNode: false, + Nonce: nonce, }) if err != nil { return nil, fmt.Errorf("p2p service: %w", err) @@ -110,7 +117,7 @@ func bootstrapNode( b.p2pService = p2ps b.p2pHalter = p2ps - hive := hive.New(p2ps, addressbook, networkID, o.BootnodeMode, o.AllowPrivateCIDRs, logger) + hive := hive.New(p2ps, addressbook, networkID, o.BootnodeMode, o.AllowPrivateCIDRs, swarmAddress, logger) if err = p2ps.AddProtocol(hive.Protocol()); err != nil { return nil, fmt.Errorf("hive service: %w", err) diff --git a/pkg/node/node.go b/pkg/node/node.go index f20468df338..56cdbc4572f 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -129,12 +129,16 @@ type Options struct { Addr string AllowPrivateCIDRs bool APIAddr string + EnableWSS bool + WSSAddr string + AutoTLSStorageDir string BlockchainRpcEndpoint string BlockProfile bool BlockTime time.Duration BootnodeMode bool Bootnodes []string CacheCapacity uint64 + AutoTLSCAEndpoint string ChainID int64 ChequebookEnable bool CORSAllowedOrigins []string @@ -145,12 +149,15 @@ type Options struct { DBWriteBufferSize uint64 EnableStorageIncentives bool EnableWS bool + AutoTLSDomain string + AutoTLSRegistrationEndpoint string FullNodeMode bool Logger log.Logger MinimumGasTipCap uint64 MinimumStorageRadius uint MutexProfile bool NATAddr string + NATWSSAddr string NeighborhoodSuggester string PaymentEarly int64 PaymentThreshold string @@ -228,6 +235,10 @@ func NewBee( return nil, fmt.Errorf("invalid NAT address %s: %w", o.NATAddr, err) } + if err := validatePublicAddress(o.NATWSSAddr); err != nil { + return nil, fmt.Errorf("invalid NAT WSS address %s: %w", o.NATWSSAddr, err) + } + ctx, ctxCancel := context.WithCancel(ctx) defer func() { // if there's been an error on this function @@ -653,14 +664,21 @@ func NewBee( } p2ps, err := libp2p.New(ctx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{ - PrivateKey: libp2pPrivateKey, - NATAddr: o.NATAddr, - EnableWS: o.EnableWS, - WelcomeMessage: o.WelcomeMessage, - FullNode: o.FullNodeMode, - Nonce: nonce, - ValidateOverlay: chainEnabled, - Registry: registry, + PrivateKey: libp2pPrivateKey, + NATAddr: o.NATAddr, + NATWSSAddr: o.NATWSSAddr, + EnableWS: o.EnableWS, + EnableWSS: o.EnableWSS, + WSSAddr: o.WSSAddr, + AutoTLSStorageDir: o.AutoTLSStorageDir, + AutoTLSDomain: o.AutoTLSDomain, + AutoTLSRegistrationEndpoint: o.AutoTLSRegistrationEndpoint, + AutoTLSCAEndpoint: o.AutoTLSCAEndpoint, + WelcomeMessage: o.WelcomeMessage, + FullNode: o.FullNodeMode, + Nonce: nonce, + ValidateOverlay: chainEnabled, + Registry: registry, }) if err != nil { return nil, fmt.Errorf("p2p service: %w", err) @@ -733,7 +751,7 @@ func NewBee( return nil, fmt.Errorf("pingpong service: %w", err) } - hive := hive.New(p2ps, addressbook, networkID, o.BootnodeMode, o.AllowPrivateCIDRs, logger) + hive := hive.New(p2ps, addressbook, networkID, o.BootnodeMode, o.AllowPrivateCIDRs, swarmAddress, logger) if err = p2ps.AddProtocol(hive.Protocol()); err != nil { return nil, fmt.Errorf("hive service: %w", err) diff --git a/pkg/p2p/libp2p/composite_resolver_test.go b/pkg/p2p/libp2p/composite_resolver_test.go new file mode 100644 index 00000000000..43a87319807 --- /dev/null +++ b/pkg/p2p/libp2p/composite_resolver_test.go @@ -0,0 +1,162 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package libp2p_test + +import ( + "errors" + "testing" + + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p" + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/internal/handshake" + ma "github.com/multiformats/go-multiaddr" +) + +// mockResolver is a mock implementation of handshake.AdvertisableAddressResolver. +type mockResolver struct { + resolveFunc func(ma.Multiaddr) (ma.Multiaddr, error) + called bool +} + +func (m *mockResolver) Resolve(addr ma.Multiaddr) (ma.Multiaddr, error) { + m.called = true + if m.resolveFunc != nil { + return m.resolveFunc(addr) + } + return addr, nil +} + +func TestCompositeAddressResolver(t *testing.T) { + t.Parallel() + + resolvedAddr, _ := ma.NewMultiaddr("/ip4/1.1.1.1/tcp/1634") + + tests := []struct { + name string + addr string + setup func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) + wantTCPCalled bool + wantWSSCalled bool + wantErr error + wantResolved bool + }{ + { + name: "wss address", + addr: "/ip4/10.233.99.40/tcp/1635/tls/sni/*.libp2p.direct/ws/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + tcpR := &mockResolver{} + wssR := &mockResolver{ + resolveFunc: func(addr ma.Multiaddr) (ma.Multiaddr, error) { + return resolvedAddr, nil + }, + } + return libp2p.NewCompositeAddressResolver(tcpR, wssR), tcpR, wssR + }, + wantWSSCalled: true, + wantResolved: true, + }, + { + name: "tcp address", + addr: "/ip4/10.233.99.40/tcp/1634/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + tcpR := &mockResolver{ + resolveFunc: func(addr ma.Multiaddr) (ma.Multiaddr, error) { + return resolvedAddr, nil + }, + } + wssR := &mockResolver{} + return libp2p.NewCompositeAddressResolver(tcpR, wssR), tcpR, wssR + }, + wantTCPCalled: true, + wantResolved: true, + }, + { + name: "deprecated wss address", + addr: "/ip4/10.233.99.40/tcp/1635/wss/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + tcpR := &mockResolver{ + resolveFunc: func(addr ma.Multiaddr) (ma.Multiaddr, error) { + return resolvedAddr, nil + }, + } + wssR := &mockResolver{} + return libp2p.NewCompositeAddressResolver(tcpR, wssR), tcpR, wssR + }, + wantTCPCalled: true, + wantResolved: true, + }, + { + name: "ws without tls", + addr: "/ip4/10.233.99.40/tcp/1635/ws/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + tcpR := &mockResolver{ + resolveFunc: func(addr ma.Multiaddr) (ma.Multiaddr, error) { + return resolvedAddr, nil + }, + } + wssR := &mockResolver{} + return libp2p.NewCompositeAddressResolver(tcpR, wssR), tcpR, wssR + }, + wantTCPCalled: true, + wantResolved: true, + }, + { + name: "nil wss resolver", + addr: "/ip4/10.233.99.40/tcp/1635/tls/sni/*.libp2p.direct/ws/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + tcpR := &mockResolver{} + return libp2p.NewCompositeAddressResolver(tcpR, nil), tcpR, nil + }, + wantWSSCalled: false, + wantTCPCalled: false, + wantResolved: false, + }, + { + name: "nil tcp resolver", + addr: "/ip4/10.233.99.40/tcp/1634/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + setup: func() (handshake.AdvertisableAddressResolver, *mockResolver, *mockResolver) { + wssR := &mockResolver{} + return libp2p.NewCompositeAddressResolver(nil, wssR), nil, wssR + }, + wantTCPCalled: false, + wantWSSCalled: false, + wantResolved: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + resolver, tcpResolver, wssResolver := tc.setup() + + addr, err := ma.NewMultiaddr(tc.addr) + if err != nil { + t.Fatal(err) + } + + got, err := resolver.Resolve(addr) + if !errors.Is(err, tc.wantErr) { + t.Errorf("got error %v, want %v", err, tc.wantErr) + } + + if tcpResolver != nil && tc.wantTCPCalled != tcpResolver.called { + t.Errorf("tcpResolver called: got %v, want %v", tcpResolver.called, tc.wantTCPCalled) + } + if wssResolver != nil && tc.wantWSSCalled != wssResolver.called { + t.Errorf("wssResolver called: got %v, want %v", wssResolver.called, tc.wantWSSCalled) + } + + if tc.wantResolved { + if !got.Equal(resolvedAddr) { + t.Errorf("got resolved addr %s, want %s", got, resolvedAddr) + } + } else { + if !got.Equal(addr) { + t.Errorf("got addr %s, want %s", got, addr) + } + } + }) + } +} diff --git a/pkg/p2p/libp2p/connections_test.go b/pkg/p2p/libp2p/connections_test.go index 42187edca9a..27ba4b7549d 100644 --- a/pkg/p2p/libp2p/connections_test.go +++ b/pkg/p2p/libp2p/connections_test.go @@ -37,6 +37,8 @@ import ( bhost "github.com/libp2p/go-libp2p/p2p/host/basic" swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" ma "github.com/multiformats/go-multiaddr" + + libp2pmock "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/mock" ) const ( @@ -86,6 +88,42 @@ func TestConnectDisconnect(t *testing.T) { expectPeersEventually(t, s1) } +// TestConnectSelf verifies that a service cannot connect to itself, +// preventing self-connection attempts. +func TestConnectSelf(t *testing.T) { + t.Parallel() + + ctx := t.Context() + + s1, _ := newService(t, 1, libp2pServiceOpts{libp2pOpts: libp2p.Options{ + FullNode: true, + }}) + + // Get own underlay addresses + addr := serviceUnderlayAddress(t, s1) + + // Attempt to connect to self + bzzAddr, err := s1.Connect(ctx, addr) + + // Should return an error + if err == nil { + t.Fatal("expected error when connecting to self, got nil") + } + + // Should contain "cannot connect to self" in error message + if !strings.Contains(err.Error(), "cannot connect to self") { + t.Fatalf("expected 'cannot connect to self' error, got: %v", err) + } + + // bzzAddr should be nil + if bzzAddr != nil { + t.Fatal("expected nil bzz address when connecting to self") + } + + // Verify no peers are connected + expectPeers(t, s1) +} + func TestConnectToLightPeer(t *testing.T) { t.Parallel() @@ -498,6 +536,15 @@ func TestConnectWithEnabledWSTransports(t *testing.T) { }, }) + defer func() { + if err := s1.Close(); err != nil { + t.Errorf("s1.Close: %v", err) + } + if err := s2.Close(); err != nil { + t.Errorf("s2.Close: %v", err) + } + }() + addr := serviceUnderlayAddress(t, s1) if _, err := s2.Connect(ctx, addr); err != nil { @@ -774,6 +821,85 @@ func TestTopologyNotifier(t *testing.T) { waitAddrSet(t, &n2disconnectedPeer.Address, &mtx, overlay1) } +func TestConnectWithAutoTLS(t *testing.T) { + t.Parallel() + + certLoaded := make(chan struct{}) + mockCertMgr := libp2pmock.NewMockP2PForgeCertMgr(func() { + close(certLoaded) + }) + + s1, _ := newService(t, 1, libp2pServiceOpts{ + libp2pOpts: libp2p.Options{ + EnableWS: true, + EnableWSS: true, + FullNode: true, + WSSAddr: ":0", + NATAddr: "127.0.0.1:1635", + NATWSSAddr: "127.0.0.1:1635", + }, + autoTLSCertManager: mockCertMgr, + }) + + select { + case <-certLoaded: + case <-time.After(time.Second): + t.Fatal("onCertLoaded callback was not triggered") + } + + if s1 == nil { + t.Fatal("service should not be nil") + } +} + +func TestConnectWithAutoTLSAndWSTransports(t *testing.T) { + t.Parallel() + + ctx := t.Context() + + s1, overlay1 := newService(t, 1, libp2pServiceOpts{ + libp2pOpts: libp2p.Options{ + EnableWS: true, + EnableWSS: true, + FullNode: true, + WSSAddr: ":0", + NATAddr: "127.0.0.1:1635", + NATWSSAddr: "127.0.0.1:1635", + }, + autoTLSCertManager: libp2pmock.NewMockP2PForgeCertMgr(nil), + }) + + s2, overlay2 := newService(t, 1, libp2pServiceOpts{ + libp2pOpts: libp2p.Options{ + EnableWS: true, + EnableWSS: true, + FullNode: true, + WSSAddr: ":0", + NATAddr: "127.0.0.1:1636", + NATWSSAddr: "127.0.0.1:1636", + }, + autoTLSCertManager: libp2pmock.NewMockP2PForgeCertMgr(nil), + }) + + defer func() { + if err := s1.Close(); err != nil { + t.Errorf("s1.Close: %v", err) + } + if err := s2.Close(); err != nil { + t.Errorf("s2.Close: %v", err) + } + }() + + addr := serviceUnderlayAddress(t, s1) + + if _, err := s2.Connect(ctx, addr); err != nil { + t.Fatal(err) + } + + expectPeers(t, s2, overlay1) + expectPeersEventually(t, s1, overlay2) +} + // TestTopologyAnnounce checks that announcement // works correctly for full nodes and light nodes. func TestTopologyAnnounce(t *testing.T) { @@ -895,8 +1021,6 @@ func TestTopologyAnnounce(t *testing.T) { } func TestTopologyOverSaturated(t *testing.T) { - t.Parallel() - var ( mtx sync.Mutex ctx = context.Background() @@ -1007,8 +1131,6 @@ func TestWithDisconnectStreams(t *testing.T) { } func TestWithBlocklistStreams(t *testing.T) { - t.Parallel() - ctx := t.Context() s1, overlay1 := newService(t, 1, libp2pServiceOpts{libp2pOpts: libp2p.Options{ diff --git a/pkg/p2p/libp2p/export_test.go b/pkg/p2p/libp2p/export_test.go index f78b9f21275..c85a85b54ae 100644 --- a/pkg/p2p/libp2p/export_test.go +++ b/pkg/p2p/libp2p/export_test.go @@ -42,3 +42,17 @@ func WithHostFactory(factory func(...libp2pm.Option) (host.Host, error)) Options hostFactory: factory, } } + +func WithAutoTLSCertManager(m autoTLSCertManager) Options { + return Options{ + autoTLSCertManager: m, + } +} + +func SetAutoTLSCertManager(o *Options, m autoTLSCertManager) { + o.autoTLSCertManager = m +} + +type AutoTLSCertManager = autoTLSCertManager + +var NewCompositeAddressResolver = newCompositeAddressResolver diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 7a537913099..6bab9b8214c 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -7,10 +7,13 @@ package libp2p import ( "context" "crypto/ecdsa" + "crypto/tls" "errors" "fmt" "net" + "net/netip" "os" + "path/filepath" "runtime" "slices" "strconv" @@ -19,6 +22,7 @@ import ( "time" ocprom "contrib.go.opencensus.io/exporter/prometheus" + "github.com/caddyserver/certmagic" "github.com/coreos/go-semver/semver" "github.com/ethersphere/bee/v2" "github.com/ethersphere/bee/v2/pkg/addressbook" @@ -31,12 +35,14 @@ import ( "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/internal/breaker" "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/internal/handshake" "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/internal/reacher" + libp2pmock "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/mock" "github.com/ethersphere/bee/v2/pkg/storage" "github.com/ethersphere/bee/v2/pkg/swarm" "github.com/ethersphere/bee/v2/pkg/topology" "github.com/ethersphere/bee/v2/pkg/topology/lightnode" "github.com/ethersphere/bee/v2/pkg/tracing" "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/config" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" @@ -52,11 +58,16 @@ import ( libp2pping "github.com/libp2p/go-libp2p/p2p/protocol/ping" "github.com/libp2p/go-libp2p/p2p/transport/tcp" ws "github.com/libp2p/go-libp2p/p2p/transport/websocket" + libp2prate "github.com/libp2p/go-libp2p/x/rate" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/multiformats/go-multistream" "github.com/prometheus/client_golang/prometheus" "go.uber.org/atomic" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + p2pforge "github.com/ipshipyard/p2p-forge/client" ) // loggerName is the tree path name of the logger for this package. @@ -84,33 +95,35 @@ const ( ) type Service struct { - ctx context.Context - host host.Host - natManager basichost.NATManager - natAddrResolver *staticAddressResolver - autonatDialer host.Host - pingDialer host.Host - libp2pPeerstore peerstore.Peerstore - metrics metrics - networkID uint64 - handshakeService *handshake.Service - addressbook addressbook.Putter - peers *peerRegistry - connectionBreaker breaker.Interface - blocklist *blocklist.Blocklist - protocols []p2p.ProtocolSpec - notifier p2p.PickyNotifier - logger log.Logger - tracer *tracing.Tracer - ready chan struct{} - halt chan struct{} - lightNodes lightnodes - lightNodeLimit int - protocolsmu sync.RWMutex - reacher p2p.Reacher - networkStatus atomic.Int32 - HeadersRWTimeout time.Duration - autoNAT autonat.AutoNAT + ctx context.Context + host host.Host + natManager basichost.NATManager + autonatDialer host.Host + pingDialer host.Host + libp2pPeerstore peerstore.Peerstore + metrics metrics + networkID uint64 + handshakeService *handshake.Service + addressbook addressbook.Putter + peers *peerRegistry + connectionBreaker breaker.Interface + blocklist *blocklist.Blocklist + protocols []p2p.ProtocolSpec + notifier p2p.PickyNotifier + logger log.Logger + tracer *tracing.Tracer + ready chan struct{} + halt chan struct{} + lightNodes lightnodes + lightNodeLimit int + protocolsmu sync.RWMutex + reacher p2p.Reacher + networkStatus atomic.Int32 + HeadersRWTimeout time.Duration + autoNAT autonat.AutoNAT + enableWS bool + autoTLSCertManager autoTLSCertManager + zapLogger *zap.Logger } type lightnodes interface { @@ -121,52 +134,72 @@ type lightnodes interface { EachPeer(pf topology.EachPeerFunc) error } +// autoTLSCertManager defines the interface for managing TLS certificates. +type autoTLSCertManager interface { + Start() error + Stop() + TLSConfig() *tls.Config + AddressFactory() config.AddrsFactory +} + type Options struct { - PrivateKey *ecdsa.PrivateKey - NATAddr string - EnableWS bool - FullNode bool - LightNodeLimit int - WelcomeMessage string - Nonce []byte - ValidateOverlay bool - hostFactory func(...libp2p.Option) (host.Host, error) - HeadersRWTimeout time.Duration - Registry *prometheus.Registry + PrivateKey *ecdsa.PrivateKey + NATAddr string + NATWSSAddr string + EnableWS bool + EnableWSS bool + WSSAddr string + AutoTLSStorageDir string + AutoTLSCAEndpoint string + AutoTLSDomain string + AutoTLSRegistrationEndpoint string + FullNode bool + LightNodeLimit int + WelcomeMessage string + Nonce []byte + ValidateOverlay bool + hostFactory func(...libp2p.Option) (host.Host, error) + HeadersRWTimeout time.Duration + Registry *prometheus.Registry + autoTLSCertManager autoTLSCertManager } -func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, logger log.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { - host, port, err := net.SplitHostPort(addr) +func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, logger log.Logger, tracer *tracing.Tracer, o Options) (s *Service, returnErr error) { + logger = logger.WithName(loggerName).Register() + + parsedAddr, err := parseAddress(addr) if err != nil { - return nil, fmt.Errorf("address: %w", err) + return nil, err } - ip4Addr := "0.0.0.0" - ip6Addr := "::" + var listenAddrs []string - if host != "" { - ip := net.ParseIP(host) - if ip4 := ip.To4(); ip4 != nil { - ip4Addr = ip4.String() - ip6Addr = "" - } else if ip6 := ip.To16(); ip6 != nil { - ip6Addr = ip6.String() - ip4Addr = "" + if parsedAddr.IP4 != "" { + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip4/%s/tcp/%s", parsedAddr.IP4, parsedAddr.Port)) + if o.EnableWS { + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip4/%s/tcp/%s/ws", parsedAddr.IP4, parsedAddr.Port)) } } - var listenAddrs []string - if ip4Addr != "" { - listenAddrs = append(listenAddrs, fmt.Sprintf("/ip4/%s/tcp/%s", ip4Addr, port)) + if parsedAddr.IP6 != "" { + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip6/%s/tcp/%s", parsedAddr.IP6, parsedAddr.Port)) if o.EnableWS { - listenAddrs = append(listenAddrs, fmt.Sprintf("/ip4/%s/tcp/%s/ws", ip4Addr, port)) + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip6/%s/tcp/%s/ws", parsedAddr.IP6, parsedAddr.Port)) } } - if ip6Addr != "" { - listenAddrs = append(listenAddrs, fmt.Sprintf("/ip6/%s/tcp/%s", ip6Addr, port)) - if o.EnableWS { - listenAddrs = append(listenAddrs, fmt.Sprintf("/ip6/%s/tcp/%s/ws", ip6Addr, port)) + if o.EnableWSS { + parsedWssAddr, err := parseAddress(o.WSSAddr) + if err != nil { + return nil, err + } + + if parsedWssAddr.IP4 != "" { + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip4/%s/tcp/%s/tls/sni/*.%s/ws", parsedWssAddr.IP4, parsedWssAddr.Port, o.AutoTLSDomain)) + } + + if parsedWssAddr.IP6 != "" { + listenAddrs = append(listenAddrs, fmt.Sprintf("/ip6/%s/tcp/%s/tls/sni/*.%s/ws", parsedWssAddr.IP6, parsedWssAddr.Port, o.AutoTLSDomain)) } } @@ -208,13 +241,141 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay return nil, err } - rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str)) + limitPerIp := rcmgr.WithLimitPerSubnet( + []rcmgr.ConnLimitPerSubnet{{PrefixLength: 32, ConnCount: 200}}, // IPv4 /32 (Single IP) -> 200 conns + []rcmgr.ConnLimitPerSubnet{{PrefixLength: 56, ConnCount: 200}}, // IPv6 /56 subnet -> 200 conns + ) + + // Custom rate limiter for connection attempts + // 20 peers cluster adaptation: + // Allow bursts of connection attempts (e.g. restart) but prevent DDOS. + connLimiter := &libp2prate.Limiter{ + // Allow unlimited local connections (same as default) + NetworkPrefixLimits: []libp2prate.PrefixLimit{ + {Prefix: netip.MustParsePrefix("127.0.0.0/8"), Limit: libp2prate.Limit{}}, + {Prefix: netip.MustParsePrefix("::1/128"), Limit: libp2prate.Limit{}}, + }, + GlobalLimit: libp2prate.Limit{}, // Unlimited global + SubnetRateLimiter: libp2prate.SubnetLimiter{ + IPv4SubnetLimits: []libp2prate.SubnetLimit{ + { + PrefixLength: 32, // Apply limits per individual IPv4 address (/32) + // Allow 10 connection attempts per second per IP, burst up to 40 + Limit: libp2prate.Limit{RPS: 10.0, Burst: 40}, + }, + }, + IPv6SubnetLimits: []libp2prate.SubnetLimit{ + { + PrefixLength: 56, // Apply limits per /56 IPv6 subnet + // Allow 10 connection attempts per second per IP, burst up to 40 + // Subnet-level limiting prevents flooding from multiple addresses in the same block. + Limit: libp2prate.Limit{RPS: 10.0, Burst: 40}, + }, + }, + // Duration to retain state for an IP or subnet after it becomes inactive. + GracePeriod: 10 * time.Second, + }, + } + + rm, err := rcmgr.NewResourceManager(limiter, rcmgr.WithTraceReporter(str), limitPerIp, rcmgr.WithConnRateLimiters(connLimiter)) if err != nil { return nil, err } var natManager basichost.NATManager + var certManager autoTLSCertManager + var zapLogger *zap.Logger + + // AutoTLS is only needed for WSS + enableAutoTLS := o.EnableWSS + + if enableAutoTLS { + if o.autoTLSCertManager != nil { + certManager = o.autoTLSCertManager + } else { + // create a zap logger needed for cert manager to be as close to + // swarm logger as possible + l, err := zap.Config{ + Level: zap.NewAtomicLevelAt(zap.DebugLevel), + Development: false, + Sampling: &zap.SamplingConfig{ + Initial: 100, + Thereafter: 100, + }, + Encoding: "json", + EncoderConfig: zapcore.EncoderConfig{ + TimeKey: "time", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller", + FunctionKey: zapcore.OmitKey, + MessageKey: "msg", + StacktraceKey: "stacktrace", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.LowercaseLevelEncoder, + EncodeTime: zapcore.EpochTimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + }, + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + }.Build() + if err != nil { + return nil, err + } + + // assing zap logger as it needs to be synced when the service stops + zapLogger = l + + defer func() { + _ = zapLogger.Sync() + }() + + // Use AutoTLS storage dir with domain subdir for easier management + // of different registers. + storagePath := filepath.Join(o.AutoTLSStorageDir, o.AutoTLSDomain) + + if err := os.MkdirAll(storagePath, 0700); err != nil { + return nil, fmt.Errorf("create certificate storage directory %s: %w", storagePath, err) + } + + certManager, err = p2pforge.NewP2PForgeCertMgr( + p2pforge.WithForgeDomain(o.AutoTLSDomain), + p2pforge.WithForgeRegistrationEndpoint(o.AutoTLSRegistrationEndpoint), + p2pforge.WithCAEndpoint(o.AutoTLSCAEndpoint), + p2pforge.WithCertificateStorage(&certmagic.FileStorage{Path: storagePath}), + p2pforge.WithLogger(zapLogger.Sugar()), + p2pforge.WithUserAgent(userAgent()), + p2pforge.WithAllowPrivateForgeAddrs(), + p2pforge.WithRegistrationDelay(0), + p2pforge.WithOnCertLoaded(func() { + logger.Info("auto tls certificate is loaded") + }), + p2pforge.WithOnCertRenewed(func() { + logger.Info("auto tls certificate is renewed") + }), + ) + if err != nil { + return nil, fmt.Errorf("initialize AutoTLS: %w", err) + } + } + + defer func() { + if returnErr != nil { + // certificate manager has to be stopped if service is not + // constructed + certManager.Stop() + } + }() + + if err := certManager.Start(); err != nil { + return nil, fmt.Errorf("start AutoTLS certificate manager: %w", err) + } + + logger.Info("AutoTLS certificate manager initialized") + } + opts := []libp2p.Option{ libp2p.ListenAddrStrings(listenAddrs...), security, @@ -224,7 +385,7 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay libp2p.ResourceManager(rm), } - if o.NATAddr == "" { + if o.NATAddr == "" && o.NATWSSAddr == "" { opts = append(opts, libp2p.NATManager(func(n network.Network) basichost.NATManager { natManager = basichost.NewNATManager(n) @@ -247,10 +408,49 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay libp2p.Transport(tcp.NewTCPTransport, tcp.DisableReuseport()), } - if o.EnableWS { + var tcpResolver handshake.AdvertisableAddressResolver + if o.NATAddr != "" { + r, err := newStaticAddressResolver(o.NATAddr, net.LookupIP) + if err != nil { + return nil, fmt.Errorf("static nat: %w", err) + } + tcpResolver = r + } + + var wssResolver handshake.AdvertisableAddressResolver + if o.EnableWSS && o.NATWSSAddr != "" { + r, err := newStaticAddressResolver(o.NATWSSAddr, net.LookupIP) + if err != nil { + return nil, fmt.Errorf("static wss nat: %w", err) + } + wssResolver = r + } + + if o.EnableWSS { + wsOpt := ws.WithTLSConfig(certManager.TLSConfig()) + transports = append(transports, libp2p.Transport(ws.New, wsOpt)) + } else if o.EnableWS { transports = append(transports, libp2p.Transport(ws.New)) } + compositeResolver := newCompositeAddressResolver(tcpResolver, wssResolver) + + var addrFactory config.AddrsFactory + if o.EnableWSS { + certManagerFactory := certManager.AddressFactory() + addrFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr { + addrs = includeNatResolvedAddresses(addrs, compositeResolver, logger) + addrs = certManagerFactory(addrs) + return addrs + } + } else { + addrFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr { + return includeNatResolvedAddresses(addrs, compositeResolver, logger) + } + } + + opts = append(opts, libp2p.AddrsFactory(addrFactory)) + opts = append(opts, transports...) if o.hostFactory == nil { @@ -263,6 +463,18 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay return nil, err } + if enableAutoTLS { + switch cm := certManager.(type) { + case *p2pforge.P2PForgeCertMgr: + cm.ProvideHost(h) + case *libp2pmock.MockP2PForgeCertMgr: + if err := cm.ProvideHost(h); err != nil { + return nil, fmt.Errorf("failed to provide host to MockP2PForgeCertMgr: %w", err) + } + default: + return nil, fmt.Errorf("unknown cert manager type") + } + } // Support same non default security and transport options as // original host. dialer, err := o.hostFactory(append(transports, security)...) @@ -270,7 +482,13 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay return nil, err } - options := []autonat.Option{autonat.EnableService(dialer.Network())} + if o.HeadersRWTimeout == 0 { + o.HeadersRWTimeout = defaultHeadersRWTimeout + } + + options := []autonat.Option{ + autonat.EnableService(dialer.Network()), + } val, err := strconv.ParseBool(reachabilityOverridePublic) if err != nil { @@ -288,25 +506,7 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay return nil, fmt.Errorf("autonat: %w", err) } - if o.HeadersRWTimeout == 0 { - o.HeadersRWTimeout = defaultHeadersRWTimeout - } - - var advertisableAddresser handshake.AdvertisableAddressResolver - var natAddrResolver *staticAddressResolver - if o.NATAddr == "" { - advertisableAddresser = &UpnpAddressResolver{ - host: h, - } - } else { - natAddrResolver, err = newStaticAddressResolver(o.NATAddr, net.LookupIP) - if err != nil { - return nil, fmt.Errorf("static nat: %w", err) - } - advertisableAddresser = natAddrResolver - } - - handshakeService, err := handshake.New(signer, advertisableAddresser, overlay, networkID, o.FullNode, o.Nonce, newHostAddresser(h), o.WelcomeMessage, o.ValidateOverlay, h.ID(), logger) + handshakeService, err := handshake.New(signer, newCompositeAddressResolver(tcpResolver, wssResolver), overlay, networkID, o.FullNode, o.Nonce, newHostAddresser(h), o.WelcomeMessage, o.ValidateOverlay, h.ID(), logger) if err != nil { return nil, fmt.Errorf("handshake service: %w", err) } @@ -322,28 +522,30 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay } peerRegistry := newPeerRegistry() - s := &Service{ - ctx: ctx, - host: h, - natManager: natManager, - natAddrResolver: natAddrResolver, - autonatDialer: dialer, - pingDialer: pingDialer, - handshakeService: handshakeService, - libp2pPeerstore: libp2pPeerstore, - metrics: newMetrics(), - networkID: networkID, - peers: peerRegistry, - addressbook: ab, - blocklist: blocklist.NewBlocklist(storer), - logger: logger.WithName(loggerName).Register(), - tracer: tracer, - connectionBreaker: breaker.NewBreaker(breaker.Options{}), // use default options - ready: make(chan struct{}), - halt: make(chan struct{}), - lightNodes: lightNodes, - HeadersRWTimeout: o.HeadersRWTimeout, - autoNAT: autoNAT, + s = &Service{ + ctx: ctx, + host: h, + natManager: natManager, + autonatDialer: dialer, + pingDialer: pingDialer, + handshakeService: handshakeService, + libp2pPeerstore: libp2pPeerstore, + metrics: newMetrics(), + networkID: networkID, + peers: peerRegistry, + addressbook: ab, + blocklist: blocklist.NewBlocklist(storer), + logger: logger, + tracer: tracer, + connectionBreaker: breaker.NewBreaker(breaker.Options{}), // use default options + ready: make(chan struct{}), + halt: make(chan struct{}), + lightNodes: lightNodes, + HeadersRWTimeout: o.HeadersRWTimeout, + autoNAT: autoNAT, + enableWS: o.EnableWS, + autoTLSCertManager: certManager, + zapLogger: zapLogger, } peerRegistry.setDisconnecter(s) @@ -369,6 +571,37 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay return s, nil } +type parsedAddress struct { + IP4 string + IP6 string + Port string +} + +func parseAddress(addr string) (*parsedAddress, error) { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil, fmt.Errorf("parse address %s: %w", addr, err) + } + + res := &parsedAddress{ + IP4: "0.0.0.0", + IP6: "::", + Port: port, + } + + if host != "" { + ip := net.ParseIP(host) + if ip4parsed := ip.To4(); ip4parsed != nil { + res.IP4 = ip4parsed.String() + res.IP6 = "" + } else if ip6parsed := ip.To16(); ip6parsed != nil { + res.IP6 = ip6parsed.String() + res.IP4 = "" + } + } + return res, nil +} + func (s *Service) reachabilityWorker() error { sub, err := s.host.EventBus().Subscribe([]any{new(event.EvtLocalReachabilityChanged)}) if err != nil { @@ -413,7 +646,7 @@ func (s *Service) handleIncoming(stream network.Stream) { peerID := stream.Conn().RemotePeer() handshakeStream := newStream(stream, s.metrics) - peerMultiaddrs, err := s.peerMultiaddrs(s.ctx, stream.Conn(), peerID) + peerMultiaddrs, err := s.peerMultiaddrs(s.ctx, peerID) if err != nil { s.logger.Debug("stream handler: handshake: build remote multiaddrs", "peer_id", peerID, "error", err) s.logger.Error(nil, "stream handler: handshake: build remote multiaddrs", "peer_id", peerID) @@ -443,7 +676,7 @@ func (s *Service) handleIncoming(stream network.Stream) { s.logger.Debug("stream handler: blocklisting: exists failed", "peer_address", overlay, "error", err) s.logger.Error(nil, "stream handler: internal error while connecting with peer", "peer_address", overlay) _ = handshakeStream.Reset() - _ = s.host.Network().ClosePeer(peerID) + _ = stream.Conn().Close() return } @@ -459,7 +692,7 @@ func (s *Service) handleIncoming(stream network.Stream) { if err = handshakeStream.FullClose(); err != nil { s.logger.Debug("stream handler: could not close stream", "peer_address", overlay, "error", err) s.logger.Error(nil, "stream handler: unable to handshake with peer", "peer_address", overlay) - _ = s.Disconnect(overlay, "unable to close handshake stream") + _ = stream.Conn().Close() } return } @@ -554,7 +787,7 @@ func (s *Service) handleIncoming(stream network.Stream) { return } - s.notifyReacherConnected(stream, overlay, peerID) + s.notifyReacherConnected(overlay, peerID) peerUserAgent := appendSpace(s.peerUserAgent(s.ctx, peerID)) s.networkStatus.Store(int32(p2p.NetworkStatusAvailable)) @@ -563,16 +796,15 @@ func (s *Service) handleIncoming(stream network.Stream) { s.logger.Debug("stream handler: successfully connected to peer (inbound)", "address", i.BzzAddress.Overlay, "light", i.LightString(), "user_agent", peerUserAgent) } -func (s *Service) notifyReacherConnected(stream network.Stream, overlay swarm.Address, peerID libp2ppeer.ID) { +func (s *Service) notifyReacherConnected(overlay swarm.Address, peerID libp2ppeer.ID) { if s.reacher == nil { return } peerAddrs := s.host.Peerstore().Addrs(peerID) - connectionAddr := stream.Conn().RemoteMultiaddr() - bestAddr := bzz.SelectBestAdvertisedAddress(peerAddrs, connectionAddr) + bestAddr := bzz.SelectBestAdvertisedAddress(peerAddrs, nil) - s.logger.Debug("selected reacher address", "peer_id", peerID, "selected_addr", bestAddr.String(), "connection_addr", connectionAddr.String(), "advertised_count", len(peerAddrs)) + s.logger.Debug("selected reacher address", "peer_id", peerID, "selected_addr", bestAddr.String(), "advertised_count", len(peerAddrs)) underlay, err := buildFullMA(bestAddr, peerID) if err != nil { @@ -680,23 +912,37 @@ func (s *Service) AddProtocol(p p2p.ProtocolSpec) (err error) { } func (s *Service) Addresses() (addresses []ma.Multiaddr, err error) { - for _, addr := range s.host.Addrs() { - a, err := buildUnderlayAddress(addr, s.host.ID()) - if err != nil { - return nil, err - } + return buildFullMAs(s.host.Addrs(), s.host.ID()) +} - addresses = append(addresses, a) +func includeNatResolvedAddresses(addrs []ma.Multiaddr, advertisableAddresser handshake.AdvertisableAddressResolver, logger log.Logger) (addresses []ma.Multiaddr) { + if advertisableAddresser == nil { + return addrs } - if s.natAddrResolver != nil && len(addresses) > 0 { - a, err := s.natAddrResolver.Resolve(addresses[0]) + + allAddrs := make([]ma.Multiaddr, 0, len(addrs)) + + for _, addr := range addrs { + allAddrs = append(allAddrs, addr) + + resolved, err := advertisableAddresser.Resolve(addr) if err != nil { - return nil, err + logger.Warning("could not resolve address", "addr", addr, "error", err) + continue + } + + if resolved.Equal(addr) { + continue + } + + if !slices.ContainsFunc(allAddrs, func(a ma.Multiaddr) bool { + return resolved.Equal(a) + }) { + allAddrs = append(allAddrs, resolved) } - addresses = append(addresses, a) } - return addresses, nil + return allAddrs } func (s *Service) NATManager() basichost.NATManager { @@ -733,16 +979,6 @@ func buildHostAddress(peerID libp2ppeer.ID) (ma.Multiaddr, error) { return ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", peerID.String())) } -func buildUnderlayAddress(addr ma.Multiaddr, peerID libp2ppeer.ID) (ma.Multiaddr, error) { - // Build host multiaddress - hostAddr, err := buildHostAddress(peerID) - if err != nil { - return nil, err - } - - return addr.Encapsulate(hostAddr), nil -} - func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *bzz.Address, err error) { loggerV1 := s.logger.V(1).Register() @@ -753,6 +989,7 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b var info *libp2ppeer.AddrInfo var peerID libp2ppeer.ID var connectErr error + skippedSelf := false // Try to connect to each underlay address one by one. // @@ -770,6 +1007,13 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b info = ai peerID = ai.ID + // Check if attempting to connect to self + if peerID == s.host.ID() { + s.logger.Debug("skipping connection to self", "peer_id", peerID, "underlay", info.Addrs) + skippedSelf = true + continue + } + hostAddr, err := buildHostAddress(info.ID) if err != nil { return nil, fmt.Errorf("build host address: %w", err) @@ -799,7 +1043,12 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b } if connectErr != nil { - return nil, fmt.Errorf("libp2p connect: %w", err) + return nil, fmt.Errorf("libp2p connect: %w", connectErr) + } + + // If we skipped all addresses due to self-connection, return an error + if skippedSelf { + return nil, fmt.Errorf("cannot connect to self") } if info == nil { @@ -814,7 +1063,7 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b handshakeStream := newStream(stream, s.metrics) - peerMultiaddrs, err := s.peerMultiaddrs(ctx, stream.Conn(), peerID) + peerMultiaddrs, err := s.peerMultiaddrs(ctx, peerID) if err != nil { _ = handshakeStream.Reset() _ = s.host.Network().ClosePeer(peerID) @@ -871,6 +1120,10 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b return nil, fmt.Errorf("connect full close %w", err) } + if !s.peers.Exists(overlay) { + return nil, p2p.ErrPeerNotFound + } + if i.FullNode { err = s.addressbook.Put(overlay, *i.BzzAddress) if err != nil { @@ -899,7 +1152,7 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b s.metrics.CreatedConnectionCount.Inc() - s.notifyReacherConnected(stream, overlay, peerID) + s.notifyReacherConnected(overlay, peerID) peerUA := appendSpace(s.peerUserAgent(ctx, peerID)) loggerV1.Debug("successfully connected to peer (outbound)", "addresses", i.BzzAddress.ShortString(), "light", i.LightString(), "user_agent", peerUA) @@ -1004,6 +1257,12 @@ func (s *Service) NewStream(ctx context.Context, overlay swarm.Address, headers return nil, p2p.ErrPeerNotFound } + // Verify if we really have an active connection + if s.host.Network().Connectedness(peerID) != network.Connected { + _ = s.Disconnect(overlay, "registry-host mismatch in NewStream") + return nil, p2p.ErrPeerNotFound + } + streamlibp2p, err := s.newStreamForPeerID(ctx, peerID, protocolName, protocolVersion, streamName) if err != nil { return nil, fmt.Errorf("new stream for peerid: %w", err) @@ -1033,6 +1292,11 @@ func (s *Service) NewStream(ctx context.Context, overlay swarm.Address, headers func (s *Service) newStreamForPeerID(ctx context.Context, peerID libp2ppeer.ID, protocolName, protocolVersion, streamName string) (network.Stream, error) { swarmStreamName := p2p.NewSwarmStreamName(protocolName, protocolVersion, streamName) + + if s.host.Network().Connectedness(peerID) != network.Connected { + s.logger.Debug("newStreamForPeerID: host not connected to peer, this will trigger a dial", "peer_id", peerID, "protocol", swarmStreamName) + } + st, err := s.host.NewStream(ctx, peerID, protocol.ID(swarmStreamName)) if err != nil { if st != nil { @@ -1053,6 +1317,9 @@ func (s *Service) newStreamForPeerID(ctx context.Context, peerID libp2ppeer.ID, } func (s *Service) Close() error { + if s.autoTLSCertManager != nil { + s.autoTLSCertManager.Stop() + } if err := s.libp2pPeerstore.Close(); err != nil { return err } @@ -1077,6 +1344,9 @@ func (s *Service) Close() error { return err } } + if s.zapLogger != nil { + _ = s.zapLogger.Sync() + } return s.host.Close() } @@ -1194,24 +1464,11 @@ func (s *Service) determineCurrentNetworkStatus(err error) error { // peerMultiaddrs builds full multiaddresses for a peer given information from // libp2p host peerstore and falling back to the remote address from the // connection. -func (s *Service) peerMultiaddrs(ctx context.Context, conn network.Conn, peerID libp2ppeer.ID) ([]ma.Multiaddr, error) { +func (s *Service) peerMultiaddrs(ctx context.Context, peerID libp2ppeer.ID) ([]ma.Multiaddr, error) { waitPeersCtx, cancel := context.WithTimeout(ctx, peerstoreWaitAddrsTimeout) defer cancel() - peerMultiaddrs, err := buildFullMAs(waitPeerAddrs(waitPeersCtx, s.host.Peerstore(), peerID), peerID) - if err != nil { - return nil, fmt.Errorf("build peer multiaddrs: %w", err) - } - - if len(peerMultiaddrs) == 0 { - fullRemoteAddress, err := buildFullMA(conn.RemoteMultiaddr(), peerID) - if err != nil { - return nil, fmt.Errorf("build full remote peer multi address: %w", err) - } - peerMultiaddrs = append(peerMultiaddrs, fullRemoteAddress) - } - - return peerMultiaddrs, nil + return buildFullMAs(waitPeerAddrs(waitPeersCtx, s.host.Peerstore(), peerID), peerID) } var version270 = *semver.Must(semver.NewVersion("2.7.0")) @@ -1290,6 +1547,40 @@ func isNetworkOrHostUnreachableError(err error) bool { return false } +type compositeAddressResolver struct { + tcpResolver handshake.AdvertisableAddressResolver + wssResolver handshake.AdvertisableAddressResolver +} + +func newCompositeAddressResolver(tcpResolver, wssResolver handshake.AdvertisableAddressResolver) handshake.AdvertisableAddressResolver { + return &compositeAddressResolver{ + tcpResolver: tcpResolver, + wssResolver: wssResolver, + } +} + +func (c *compositeAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) { + protocols := observedAddress.Protocols() + + containsProtocol := func(protocols []ma.Protocol, code int) bool { + return slices.ContainsFunc(protocols, func(p ma.Protocol) bool { return p.Code == code }) + } + + // ma.P_WSS protocol is deprecated, multiaddrs should comtain WS and TLS protocols for WSS + isWSS := containsProtocol(protocols, ma.P_WS) && containsProtocol(protocols, ma.P_TLS) + + if isWSS { + if c.wssResolver != nil { + return c.wssResolver.Resolve(observedAddress) + } + } else { + if c.tcpResolver != nil { + return c.tcpResolver.Resolve(observedAddress) + } + } + return observedAddress, nil +} + type hostAddresser struct { host host.Host } diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index 85208272f1c..ede9cbbcb79 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -27,13 +27,14 @@ import ( ) type libp2pServiceOpts struct { - Logger log.Logger - Addressbook addressbook.Interface - PrivateKey *ecdsa.PrivateKey - MockPeerKey *ecdsa.PrivateKey - libp2pOpts libp2p.Options - lightNodes *lightnode.Container - notifier p2p.PickyNotifier + Logger log.Logger + Addressbook addressbook.Interface + PrivateKey *ecdsa.PrivateKey + MockPeerKey *ecdsa.PrivateKey + libp2pOpts libp2p.Options + lightNodes *lightnode.Container + notifier p2p.PickyNotifier + autoTLSCertManager libp2p.AutoTLSCertManager } // newService constructs a new libp2p service. @@ -81,6 +82,10 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. opts := o.libp2pOpts opts.Nonce = nonce + if o.autoTLSCertManager != nil { + libp2p.SetAutoTLSCertManager(&opts, o.autoTLSCertManager) + } + s, err = libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, o.Addressbook, statestore, o.lightNodes, o.Logger, nil, opts) if err != nil { t.Fatal(err) @@ -128,7 +133,7 @@ func expectPeersEventually(t *testing.T, s *libp2p.Service, addrs ...swarm.Addre t.Helper() var peers []p2p.Peer - err := spinlock.Wait(time.Second, func() bool { + err := spinlock.Wait(5*time.Second, func() bool { peers = s.Peers() return len(peers) == len(addrs) diff --git a/pkg/p2p/libp2p/libp2ptest/buffer.go b/pkg/p2p/libp2p/libp2ptest/buffer.go new file mode 100644 index 00000000000..ed98e09b285 --- /dev/null +++ b/pkg/p2p/libp2p/libp2ptest/buffer.go @@ -0,0 +1,28 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package libp2ptest + +import ( + "bytes" + "sync" +) + +// SafeBuffer is a thread-safe bytes.Buffer. +type SafeBuffer struct { + b bytes.Buffer + m sync.Mutex +} + +func (s *SafeBuffer) Write(p []byte) (n int, err error) { + s.m.Lock() + defer s.m.Unlock() + return s.b.Write(p) +} + +func (s *SafeBuffer) String() string { + s.m.Lock() + defer s.m.Unlock() + return s.b.String() +} diff --git a/pkg/p2p/libp2p/libp2ptest/service.go b/pkg/p2p/libp2p/libp2ptest/service.go new file mode 100644 index 00000000000..8a62531f342 --- /dev/null +++ b/pkg/p2p/libp2p/libp2ptest/service.go @@ -0,0 +1,69 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package libp2ptest + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethersphere/bee/v2/pkg/addressbook" + "github.com/ethersphere/bee/v2/pkg/crypto" + "github.com/ethersphere/bee/v2/pkg/log" + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p" + "github.com/ethersphere/bee/v2/pkg/statestore/mock" + "github.com/ethersphere/bee/v2/pkg/swarm" + "github.com/ethersphere/bee/v2/pkg/topology/lightnode" + "github.com/ethersphere/bee/v2/pkg/util/testutil" +) + +// NewLibp2pService creates a new libp2p service for testing purposes. +func NewLibp2pService(t *testing.T, networkID uint64, logger log.Logger) (*libp2p.Service, swarm.Address) { + t.Helper() + + swarmKey, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + + nonce := common.HexToHash("0x1").Bytes() + + overlay, err := crypto.NewOverlayAddress(swarmKey.PublicKey, networkID, nonce) + if err != nil { + t.Fatal(err) + } + + addr := ":0" + + statestore := mock.NewStateStore() + ab := addressbook.New(statestore) + + libp2pKey, err := crypto.GenerateSecp256r1Key() + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + lightNodes := lightnode.NewContainer(overlay) + + opts := libp2p.Options{ + PrivateKey: libp2pKey, + Nonce: nonce, + FullNode: true, + NATAddr: "127.0.0.1:0", // Disable default NAT manager + } + + s, err := libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, ab, statestore, lightNodes, logger, nil, opts) + if err != nil { + t.Fatal(err) + } + testutil.CleanupCloser(t, s) + + _ = s.Ready() + + return s, overlay +} diff --git a/pkg/p2p/libp2p/mock/mock_certmagic.go b/pkg/p2p/libp2p/mock/mock_certmagic.go new file mode 100644 index 00000000000..8337f26e8ab --- /dev/null +++ b/pkg/p2p/libp2p/mock/mock_certmagic.go @@ -0,0 +1,158 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package mock + +import ( + "context" + "crypto/tls" + "sync" + + _ "embed" + + "github.com/libp2p/go-libp2p/config" + "github.com/libp2p/go-libp2p/core/host" + ma "github.com/multiformats/go-multiaddr" +) + +//go:embed testdata/cert.pem +var certPEM []byte + +//go:embed testdata/key.pem +var keyPEM []byte + +// MockFileStorage is a minimal implementation of certmagic.FileStorage for testing. +type MockFileStorage struct { + path string +} + +func NewMockFileStorage(path string) *MockFileStorage { + return &MockFileStorage{path: path} +} + +func (m *MockFileStorage) Store(_ context.Context, _ string, _ []byte) error { + return nil +} + +func (m *MockFileStorage) Load(_ context.Context, _ string) ([]byte, error) { + return nil, nil +} + +func (m *MockFileStorage) Delete(_ context.Context, _ string) error { + return nil +} + +func (m *MockFileStorage) Exists(_ context.Context, _ string) (bool, error) { + return false, nil +} + +func (m *MockFileStorage) List(_ context.Context, _ string, _ bool) ([]string, error) { + return nil, nil +} + +func (m *MockFileStorage) Lock(_ context.Context, _ string) error { + return nil +} + +func (m *MockFileStorage) Unlock(_ context.Context, _ string) error { + return nil +} + +// MockCache is a minimal implementation of certmagic.Cache for testing. +type MockCache struct { + stopped bool + mu sync.Mutex +} + +func NewMockCache() *MockCache { + return &MockCache{} +} + +func (m *MockCache) Stop() { + m.mu.Lock() + defer m.mu.Unlock() + m.stopped = true +} + +// MockConfig is a minimal implementation of certmagic.Config for testing. +type MockConfig struct { + cache *MockCache +} + +func NewMockConfig() *MockConfig { + return &MockConfig{cache: NewMockCache()} +} + +func (m *MockConfig) TLSConfig() *tls.Config { + return &tls.Config{ + MinVersion: tls.VersionTLS12, + } +} + +// MockP2PForgeCertMgr is a mock implementation of p2pforge.P2PForgeCertMgr. +type MockP2PForgeCertMgr struct { + cache *MockCache + onCertLoaded func() + started bool + mu sync.Mutex + ProvideHost func(host.Host) error +} + +func NewMockP2PForgeCertMgr(onCertLoaded func()) *MockP2PForgeCertMgr { + return &MockP2PForgeCertMgr{ + cache: NewMockCache(), + onCertLoaded: onCertLoaded, + ProvideHost: func(_ host.Host) error { return nil }, + } +} + +func (m *MockP2PForgeCertMgr) Start() error { + m.mu.Lock() + defer m.mu.Unlock() + if m.started { + return nil + } + m.started = true + if m.onCertLoaded != nil { + go func() { + m.onCertLoaded() + }() + } + return nil +} +func (m *MockP2PForgeCertMgr) Stop() { + m.mu.Lock() + defer m.mu.Unlock() + if !m.started { + return + } + m.started = false + m.cache.Stop() +} + +func (m *MockP2PForgeCertMgr) TLSConfig() *tls.Config { + // Use tls.X509KeyPair to create a certificate from the hardcoded strings + cert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + // This should not fail if the strings are pasted correctly + return nil + } + + return &tls.Config{Certificates: []tls.Certificate{cert}} +} + +func (m *MockP2PForgeCertMgr) SetOnCertLoaded(cb func()) { + m.mu.Lock() + defer m.mu.Unlock() + m.onCertLoaded = cb +} + +func (m *MockP2PForgeCertMgr) AddressFactory() config.AddrsFactory { + return func(addrs []ma.Multiaddr) []ma.Multiaddr { + return addrs + } +} + +func (m *MockP2PForgeCertMgr) GetCache() *MockCache { + return m.cache +} diff --git a/pkg/p2p/libp2p/mock/mock_certmagic_test.go b/pkg/p2p/libp2p/mock/mock_certmagic_test.go new file mode 100644 index 00000000000..93dd0d159b6 --- /dev/null +++ b/pkg/p2p/libp2p/mock/mock_certmagic_test.go @@ -0,0 +1,112 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mock_test + +import ( + "crypto/tls" + "testing" + "time" + + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/mock" + ma "github.com/multiformats/go-multiaddr" +) + +func TestMockP2PForgeCertMgr_Start(t *testing.T) { + certLoaded := make(chan struct{}) + mgr := mock.NewMockP2PForgeCertMgr(func() { + close(certLoaded) + }) + + if err := mgr.Start(); err != nil { + t.Fatalf("Start() error = %v, wantErr %v", err, nil) + } + + select { + case <-certLoaded: + case <-time.After(time.Second): + t.Fatal("onCertLoaded callback was not triggered") + } + + // Test idempotency + if err := mgr.Start(); err != nil { + t.Fatalf("Start() second call error = %v, wantErr %v", err, nil) + } +} + +func TestMockP2PForgeCertMgr_Stop(t *testing.T) { + mgr := mock.NewMockP2PForgeCertMgr(nil) + + if err := mgr.Start(); err != nil { + t.Fatalf("Start() error = %v, wantErr %v", err, nil) + } + + mgr.Stop() + + // Test idempotency + mgr.Stop() +} + +func TestMockP2PForgeCertMgr_TLSConfig(t *testing.T) { + mgr := mock.NewMockP2PForgeCertMgr(nil) + cfg := mgr.TLSConfig() + + if cfg == nil { + t.Fatal("TLSConfig() returned nil") + } + + if len(cfg.Certificates) == 0 { + t.Error("TLSConfig() returned no certificates") + } +} + +func TestMockP2PForgeCertMgr_AddressFactory(t *testing.T) { + mgr := mock.NewMockP2PForgeCertMgr(nil) + factory := mgr.AddressFactory() + + addr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0") + addrs := []ma.Multiaddr{addr} + + got := factory(addrs) + if len(got) != 1 || !got[0].Equal(addr) { + t.Errorf("AddressFactory() = %v, want %v", got, addrs) + } +} + +func TestMockP2PForgeCertMgr_SetOnCertLoaded(t *testing.T) { + mgr := mock.NewMockP2PForgeCertMgr(nil) + certLoaded := make(chan struct{}) + + mgr.SetOnCertLoaded(func() { + close(certLoaded) + }) + + if err := mgr.Start(); err != nil { + t.Fatalf("Start() error = %v, wantErr %v", err, nil) + } + + select { + case <-certLoaded: + case <-time.After(time.Second): + t.Fatal("onCertLoaded callback was not triggered after SetOnCertLoaded") + } +} + +func TestMockP2PForgeCertMgr_GetCache(t *testing.T) { + mgr := mock.NewMockP2PForgeCertMgr(nil) + if mgr.GetCache() == nil { + t.Error("GetCache() returned nil") + } +} + +func TestMockConfig(t *testing.T) { + cfg := mock.NewMockConfig() + tlsCfg := cfg.TLSConfig() + if tlsCfg == nil { + t.Fatal("TLSConfig() returned nil") + } + if tlsCfg.MinVersion != tls.VersionTLS12 { + t.Errorf("TLSConfig().MinVersion = %v, want %v", tlsCfg.MinVersion, tls.VersionTLS12) + } +} diff --git a/pkg/p2p/libp2p/mock/testdata/cert.pem b/pkg/p2p/libp2p/mock/testdata/cert.pem new file mode 100644 index 00000000000..942876e1fac --- /dev/null +++ b/pkg/p2p/libp2p/mock/testdata/cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCzCCAfOgAwIBAgIUYmVQGLnuPXQb8yC4X69ll6FQjWQwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTI1MDgwMTA3MzA0OFoYDzIxMjUw +NzA4MDczMDQ4WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC/NbDVAd4OdVMNiK+BjAFyTCIiJssgxhi6rWEgzykV +6lv0Q4/loUCwp1ylh6LJa6yjioGmxXl2CqIALcxRXg/DopJFgfIPPhghSHVE6AvV +PGf+Qw85vXfdjX6qymPsRRz5mMj9N9BidL1HgJjxpGw+7aDwXxMCvxwFN46kyfb9 +fawIIlAJv2gxBoKxf+8AXwimPUrXxG1HziMPNTjQGW+zVRzeK4pTNdt+CXcf4vLM +LKv7eRXYiAL7m/6/UE/SQOXDGxvjkOTWgVX2gcV9tMZOaFJBp/WycsexiajRRxLQ +tl1weQhyBmLA7N494sYpwmzF1feybkkrPeU7Vo7T2gLrAgMBAAGjUzBRMB0GA1Ud +DgQWBBRs/abpJGBaT14jL05Fj9PVbc7T4TAfBgNVHSMEGDAWgBRs/abpJGBaT14j +L05Fj9PVbc7T4TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA1 +mhrBSvtlW4mhxQAAEfX/JotieeGuG9nUE75LJ+sW5mRDO+5PZeHAajBdWFGftCm2 +vNONQMVkAt8PSPuZ+6t284HSpWLTgYGTu19m9JFDfw3Dj7HIX95c0xq1WdNSDvpR +kRfoe7yc4B6mCKIU4EjAv0lUs21I2oLIbqQdhJneivutyCYcV/hxt7OJZs92g9HX +S8MGeWRCFhoPoOQ9tvszqzf7AB3uqiRuFxk2DkuZ7yN63/+DGj2kTBkf3Qe+4DyS +7DK5XkPdl/ajTXNoLdgYUw/5hdsbcTjnxRr37eKqoa/MtQxzQjoA5HWYoaDX+Vzp +OwmvrIFPPZ+bU+6+Xs5i +-----END CERTIFICATE----- diff --git a/pkg/p2p/libp2p/mock/testdata/key.pem b/pkg/p2p/libp2p/mock/testdata/key.pem new file mode 100644 index 00000000000..9668c2e083f --- /dev/null +++ b/pkg/p2p/libp2p/mock/testdata/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/NbDVAd4OdVMN +iK+BjAFyTCIiJssgxhi6rWEgzykV6lv0Q4/loUCwp1ylh6LJa6yjioGmxXl2CqIA +LcxRXg/DopJFgfIPPhghSHVE6AvVPGf+Qw85vXfdjX6qymPsRRz5mMj9N9BidL1H +gJjxpGw+7aDwXxMCvxwFN46kyfb9fawIIlAJv2gxBoKxf+8AXwimPUrXxG1HziMP +NTjQGW+zVRzeK4pTNdt+CXcf4vLMLKv7eRXYiAL7m/6/UE/SQOXDGxvjkOTWgVX2 +gcV9tMZOaFJBp/WycsexiajRRxLQtl1weQhyBmLA7N494sYpwmzF1feybkkrPeU7 +Vo7T2gLrAgMBAAECggEAAlN0carm2Q7pUAgAVX3d4SvUyhEZNdCNw1MNeqgP0IUi +a22y1uyjjC9i4PdputYh+3bqgS1JdpmB6botbiQY0XZkyGQCt9fAB9yvjZRmylCz +b0mNe23l+lo2lvPimLGxmrTjZUwbfCR1m0Jupqoi4TqOud7nRohxwIQ6Zjmm3Y53 +Ybiv8h46mhy2NZFI2zwaO9q0MpYozCsCR5Xi6DasJZedlAB+185mTJo79e2AllPI +Y3tsQLgrCc2i9TAoEjvJdCxNDuElusabKgROj3DPr2LEkApeX2EdknNKqMIb+NIk +7htDSYjoJuG1ABRB0vBx7s0OGtk+IC/xYwdYB8wgdQKBgQDszNAHHUGbBr2yh8MP +JXqcoxXiDMOjyrrJcTzkUGXP2tCG05u+do8e4Or1K6WXKJGuITeewd6cW/HE2Mlt +sc58b+6+H3hm1dkuAOj+uF6mV8Al2TxVoRrKlAojAzu9QhkH+9GYR+nGqz7wKSnS +6EQETiCfd5LYrK0OH12wOla+JQKBgQDOtpLWroD5Vjf4KJ2qX4un2V2IKyWMcofH +t4qWbD+6F4Kt/ZCxFKviLBwRffGaatp7E1W0kU76oflsrnpRzSzMearlLIIid8nA +ucXCuyJdQPSivsHJJM6MMQ4BzT2stR8JDtJMNip/JUb0pZFS/aG1BCp+nLSoU23m +q7vyUvJHzwKBgQDcaCaY+Jo/+Z5HtiXQy0m80e9kYA0ZP3FsXoIW4N5jAYBmfj/Q +n/nG/AK2ANI4SAKQ2Uoz8q+JSetXFZEnEQDowiatwA0JarKjJyW3MVSn77VhhTmr +WjDdrb1hqXjJR+SUkcccvpLR4ELMtwO+04G7oBytUVbVZqQNKRTDGwnyIQKBgD+t +1KxX05l76wACmxdqGZ6agoq5J/cNLTDkJMhUDomoRnSNAW7bvFuPVRI6Zxw3wJhb +i3J1tQvWq/zD/yCGAT/4VyIERQ6TMk6xq+9iMKLjqLkd5JqvQQXE8tixPkefADGN +JFGf+hVzCVnCS3NyeMdHwkOAyNJ16Qw/aUWsMcDXAoGBAJpIdS7fu7Odxp76ssjy +AUsUFvGLH3rndYUWANy9xmz5FAxt4pZAbtbIYqPXy+4hpXWhqgOmTti8GDqL1W8g +CdYKvjVOHj5GNMQ6QJ3b1MDmUOeSgaN7NIY7SuKlKT54nYkplej9cd/4h1DpjHar +3eEDaJABlw0eDY7F2qXJZzZ3 +-----END PRIVATE KEY----- diff --git a/pkg/p2p/libp2p/protocols_test.go b/pkg/p2p/libp2p/protocols_test.go index 30c9f8504f1..0bec5ba49af 100644 --- a/pkg/p2p/libp2p/protocols_test.go +++ b/pkg/p2p/libp2p/protocols_test.go @@ -18,8 +18,7 @@ import ( libp2pm "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/host" protocol "github.com/libp2p/go-libp2p/core/protocol" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" - swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" + ma "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multistream" ) @@ -398,25 +397,29 @@ func TestPing(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() + listenAddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0") + if err != nil { + t.Fatal(err) + } + + hostFactory := libp2p.WithHostFactory( + func(opts ...libp2pm.Option) (host.Host, error) { + opts = append(opts, libp2pm.ListenAddrs(listenAddr)) + + h, err := libp2pm.New(opts...) + if err != nil { + return nil, err + } + return h, nil + }, + ) + s1, _ := newService(t, 1, libp2pServiceOpts{ - libp2pOpts: libp2p.WithHostFactory( - func(...libp2pm.Option) (host.Host, error) { - return bhost.NewHost(swarmt.GenSwarm(t), &bhost.HostOpts{EnablePing: true}) - }, - ), + libp2pOpts: hostFactory, }) s2, _ := newService(t, 1, libp2pServiceOpts{ - libp2pOpts: libp2p.WithHostFactory( - func(...libp2pm.Option) (host.Host, error) { - host, err := bhost.NewHost(swarmt.GenSwarm(t), &bhost.HostOpts{EnablePing: true}) - if err != nil { - t.Fatalf("start host: %v", err) - } - host.Start() - return host, nil - }, - ), + libp2pOpts: hostFactory, }) addr := serviceUnderlayAddress(t, s1) diff --git a/pkg/p2p/libp2p/static_resolver.go b/pkg/p2p/libp2p/static_resolver.go index c5416862e1b..5927b2b022a 100644 --- a/pkg/p2p/libp2p/static_resolver.go +++ b/pkg/p2p/libp2p/static_resolver.go @@ -5,12 +5,10 @@ package libp2p import ( - "errors" "fmt" "net" "strings" - libp2ppeer "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" ) @@ -40,16 +38,7 @@ func newStaticAddressResolver(addr string, lookupIP func(host string) ([]net.IP, } func (r *staticAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) { - observableAddrInfo, err := libp2ppeer.AddrInfoFromP2pAddr(observedAddress) - if err != nil { - return nil, err - } - - if len(observableAddrInfo.Addrs) < 1 { - return nil, errors.New("invalid observed address") - } - - observedAddrSplit := strings.Split(observableAddrInfo.Addrs[0].String(), "/") + observedAddrSplit := strings.Split(observedAddress.String(), "/") // if address is not in a form of '/ipversion/ip/protocol/port/...` don't compare to addresses and return it if len(observedAddrSplit) < 5 { @@ -69,12 +58,55 @@ func (r *staticAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multia } else { port = observedAddrSplit[4] } - a, err := ma.NewMultiaddr(multiProto + "/" + observedAddrSplit[3] + "/" + port) + + const ipv4 = "ip4" + const ipv6 = "ip6" + + // replace sni protocol ip subdomain in domain name + otherComponents := observedAddrSplit[5:] + ipSplit := strings.Split(multiProto, "/") + expectedIPSniHost := newIPSniHost(observedAddrSplit[2], observedAddrSplit[1] == ipv4) + if len(ipSplit) == 3 && (ipSplit[1] == ipv4 || ipSplit[1] == ipv6) { + for i, part := range otherComponents { + if part == "sni" && i+1 < len(otherComponents) { + ip := ipSplit[2] + isIPv4 := ipSplit[1] == ipv4 + + sniParts := strings.Split(otherComponents[i+1], ".") + if len(sniParts) > 0 { + if sniParts[0] != expectedIPSniHost { + continue + } + sniParts[0] = newIPSniHost(ip, isIPv4) + otherComponents[i+1] = strings.Join(sniParts, ".") + } + break // assume only one sni component + } + } + } + + a, err := ma.NewMultiaddr(multiProto + "/" + observedAddrSplit[3] + "/" + port + "/" + strings.Join(otherComponents, "/")) if err != nil { return nil, err } - return buildUnderlayAddress(a, observableAddrInfo.ID) + return a, nil +} + +func newIPSniHost(ip string, isIPv4 bool) string { + if isIPv4 { + return strings.ReplaceAll(ip, ".", "-") + } + + // IPv6 + newSniHost := strings.ReplaceAll(ip, ":", "-") + if newSniHost[0] == '-' { + newSniHost = "0" + newSniHost + } + if newSniHost[len(newSniHost)-1] == '-' { + newSniHost = newSniHost + "0" + } + return newSniHost } func getMultiProto(host string, lookupIP func(host string) ([]net.IP, error)) (string, error) { diff --git a/pkg/p2p/libp2p/static_resolver_test.go b/pkg/p2p/libp2p/static_resolver_test.go index c45cce0142f..8e9f022721d 100644 --- a/pkg/p2p/libp2p/static_resolver_test.go +++ b/pkg/p2p/libp2p/static_resolver_test.go @@ -27,6 +27,12 @@ func TestStaticAddressResolver(t *testing.T) { observableAddress: "/ip4/127.0.0.1/tcp/7071/p2p/16Uiu2HAkyyGKpjBiCkVqCKoJa6RzzZw9Nr7hGogsMPcdad1KyMmd", want: "/ip4/127.0.0.1/tcp/30123/p2p/16Uiu2HAkyyGKpjBiCkVqCKoJa6RzzZw9Nr7hGogsMPcdad1KyMmd", }, + { + name: "without p2p protocols", + natAddr: ":30123", + observableAddress: "/ip4/127.0.0.1/tcp/7071", + want: "/ip4/127.0.0.1/tcp/30123", + }, { name: "replace ip v4", natAddr: "192.168.1.34:", @@ -81,10 +87,38 @@ func TestStaticAddressResolver(t *testing.T) { observableAddress: "/ip4/127.0.0.1/tcp/7071/p2p/16Uiu2HAkyyGKpjBiCkVqCKoJa6RzzZw9Nr7hGogsMPcdad1KyMmd", want: "/dns/ipv4and6.com/tcp/30777/p2p/16Uiu2HAkyyGKpjBiCkVqCKoJa6RzzZw9Nr7hGogsMPcdad1KyMmd", }, + { + name: "replace ip and port with complex multiaddr", + natAddr: "192.168.1.34:30777", + observableAddress: "/ip4/10.233.99.40/tcp/1635/tls/sni/*.libp2p.direct/ws/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + want: "/ip4/192.168.1.34/tcp/30777/tls/sni/*.libp2p.direct/ws/p2p/QmWbXocGMpfa8zApx9kCNwfmc35bbRJv136bdtuQjbR4wL", + }, + { + name: "replace ip and port with complex multiaddr without p2p protocol", + natAddr: "192.168.1.34:30777", + observableAddress: "/ip4/10.233.99.40/tcp/1635/tls/sni/*.libp2p.direct/ws", + want: "/ip4/192.168.1.34/tcp/30777/tls/sni/*.libp2p.direct/ws", + }, + { + name: "replace ip and port with complex multiaddr without p2p protocol and with full domain", + natAddr: "192.168.1.34:30777", + observableAddress: "/ip4/10.233.99.40/tcp/1635/tls/sni/10-233-99-40.k2k4r8nnyi7fa2p2t2fjfam2vdyk5esk1iwlfkdz1yezu56o0o0b966w.libp2p.direct/ws", + want: "/ip4/192.168.1.34/tcp/30777/tls/sni/192-168-1-34.k2k4r8nnyi7fa2p2t2fjfam2vdyk5esk1iwlfkdz1yezu56o0o0b966w.libp2p.direct/ws", + }, + { + name: "replace ip v6 and port with complex multiaddr without p2p protocol and with full domain", + natAddr: "[::1]:30777", + observableAddress: "/ip4/10.233.99.40/tcp/1635/tls/sni/10-233-99-40.k2k4r8nnyi7fa2p2t2fjfam2vdyk5esk1iwlfkdz1yezu56o0o0b966w.libp2p.direct/ws", + want: "/ip6/::1/tcp/30777/tls/sni/0--1.k2k4r8nnyi7fa2p2t2fjfam2vdyk5esk1iwlfkdz1yezu56o0o0b966w.libp2p.direct/ws", + }, + { + name: "do not change arbitrary sni domain", + natAddr: "[::1]:30777", + observableAddress: "/ip4/10.233.99.40/tcp/1635/tls/sni/some-node.ethswarm.org/ws", + want: "/ip6/::1/tcp/30777/tls/sni/some-node.ethswarm.org/ws", + }, } { t.Run(tc.name, func(t *testing.T) { - t.Parallel() - r, err := libp2p.NewStaticAddressResolver(tc.natAddr, func(host string) ([]net.IP, error) { hosts := map[string][]net.IP{ "ipv4.com": { diff --git a/pkg/p2p/libp2p/upnp.go b/pkg/p2p/libp2p/upnp.go deleted file mode 100644 index e0dcc3f577e..00000000000 --- a/pkg/p2p/libp2p/upnp.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2020 The Swarm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package libp2p - -import ( - "errors" - "strings" - - "github.com/libp2p/go-libp2p/core/host" - libp2ppeer "github.com/libp2p/go-libp2p/core/peer" - ma "github.com/multiformats/go-multiaddr" -) - -type UpnpAddressResolver struct { - host host.Host -} - -// Resolve checks if there is a possible better advertisable underlay then the provided observed address. -// In some NAT situations, for example in the case when nodes are behind upnp, observer might send the observed address with a wrong port. -// In this case, observed address is compared to addresses provided by host, and if there is a same address but with different port, that one is used as advertisable address instead of provided observed one. -// TODO: this is a quickfix and it will be improved in the future -func (r *UpnpAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) { - observableAddrInfo, err := libp2ppeer.AddrInfoFromP2pAddr(observedAddress) - if err != nil { - return nil, err - } - - if len(observableAddrInfo.Addrs) < 1 { - return nil, errors.New("invalid observed address") - } - - observedAddrSplit := strings.Split(observableAddrInfo.Addrs[0].String(), "/") - - // if address is not in a form of '/ipversion/ip/protocol/port/...` don't compare to addresses and return it - if len(observedAddrSplit) < 5 { - return observedAddress, nil - } - - observedAddressPort := observedAddrSplit[4] - - // observervedAddressShort is an obaserved address without port - observervedAddressShort := strings.Join(append(observedAddrSplit[:4], observedAddrSplit[5:]...), "/") - - for _, a := range r.host.Addrs() { - asplit := strings.Split(a.String(), "/") - if len(asplit) != len(observedAddrSplit) { - continue - } - - aport := asplit[4] - if strings.Join(append(asplit[:4], asplit[5:]...), "/") != observervedAddressShort { - continue - } - - if aport != observedAddressPort { - aaddress, err := buildUnderlayAddress(a, observableAddrInfo.ID) - if err != nil { - continue - } - - return aaddress, nil - } - } - - return observedAddress, nil -} diff --git a/pkg/puller/puller.go b/pkg/puller/puller.go index d53a45348e4..0bcdcfae9cb 100644 --- a/pkg/puller/puller.go +++ b/pkg/puller/puller.go @@ -191,9 +191,7 @@ func (p *Puller) manage(ctx context.Context) { // disconnectPeer cancels all existing syncing and removes the peer entry from the syncing map. // Must be called under lock. func (p *Puller) disconnectPeer(addr swarm.Address) { - loggerV2 := p.logger.V(2).Register() - - loggerV2.Debug("disconnecting peer", "peer_address", addr) + p.logger.Debug("disconnecting peer", "peer_address", addr) if peer, ok := p.syncPeers[addr.ByteString()]; ok { peer.mtx.Lock() peer.stop() @@ -300,8 +298,6 @@ func (p *Puller) syncPeer(ctx context.Context, peer *syncPeer, storageRadius uin // syncPeerBin will start historical and live syncing for the peer for a particular bin. // Must be called under syncPeer lock. func (p *Puller) syncPeerBin(parentCtx context.Context, peer *syncPeer, bin uint8, cursor uint64) { - loggerV2 := p.logger.V(2).Register() - ctx, cancel := context.WithCancel(parentCtx) peer.setBinCancel(cancel, bin) @@ -331,14 +327,13 @@ func (p *Puller) syncPeerBin(parentCtx context.Context, peer *syncPeer, bin uint select { case <-ctx.Done(): - loggerV2.Debug("syncWorker context cancelled", "peer_address", address, "bin", bin) + p.logger.Debug("syncWorker context cancelled", "peer_address", address, "bin", bin) return default: } p.metrics.SyncWorkerIterCounter.Inc() - syncStart := time.Now() top, count, err := p.syncer.Sync(ctx, address, bin, start) if top == math.MaxUint64 { @@ -353,7 +348,7 @@ func (p *Puller) syncPeerBin(parentCtx context.Context, peer *syncPeer, bin uint p.logger.Debug("syncWorker interval failed, quitting", "error", err, "peer_address", address, "bin", bin, "cursor", cursor, "start", start, "topmost", top) return } - loggerV2.Debug("syncWorker interval failed", "error", err, "peer_address", address, "bin", bin, "cursor", cursor, "start", start, "topmost", top) + p.logger.Debug("syncWorker interval failed", "error", err, "peer_address", address, "bin", bin, "cursor", cursor, "start", start, "topmost", top) } _ = p.limiter.WaitN(ctx, count) @@ -372,7 +367,6 @@ func (p *Puller) syncPeerBin(parentCtx context.Context, peer *syncPeer, bin uint p.logger.Error(err, "syncWorker could not persist interval for peer, quitting", "peer_address", address) return } - loggerV2.Debug("syncWorker pulled", "bin", bin, "start", start, "topmost", top, "isHistorical", isHistorical, "duration", time.Since(syncStart), "peer_address", address) start = top + 1 } } diff --git a/pkg/pullsync/pullsync.go b/pkg/pullsync/pullsync.go index 064099e765c..436600a2f76 100644 --- a/pkg/pullsync/pullsync.go +++ b/pkg/pullsync/pullsync.go @@ -49,7 +49,6 @@ const ( MaxCursor = math.MaxUint64 DefaultMaxPage uint64 = 250 pageTimeout = time.Second - makeOfferTimeout = 15 * time.Minute handleMaxChunksPerSecond = 250 handleRequestsLimitRate = time.Second / handleMaxChunksPerSecond // handle max `handleMaxChunksPerSecond` chunks per second per peer ) @@ -228,7 +227,7 @@ func (s *Syncer) handler(streamCtx context.Context, p p2p.Peer, stream p2p.Strea // Sync syncs a batch of chunks starting at a start BinID. // It returns the BinID of highest chunk that was synced from the given // batch and the total number of chunks the downstream peer has sent. -func (s *Syncer) Sync(ctx context.Context, peer swarm.Address, bin uint8, start uint64) (uint64, int, error) { +func (s *Syncer) Sync(ctx context.Context, peer swarm.Address, bin uint8, start uint64) (topmost uint64, count int, err error) { stream, err := s.streamer.NewStream(ctx, peer, nil, protocolName, protocolVersion, streamName) if err != nil { @@ -237,7 +236,6 @@ func (s *Syncer) Sync(ctx context.Context, peer swarm.Address, bin uint8, start defer func() { if err != nil { _ = stream.Reset() - s.logger.Debug("error syncing peer", "peer_address", peer, "bin", bin, "start", start, "error", err) } else { stream.FullClose() } @@ -261,7 +259,7 @@ func (s *Syncer) Sync(ctx context.Context, peer swarm.Address, bin uint8, start return offer.Topmost, 0, nil } - topmost := offer.Topmost + topmost = offer.Topmost var ( bvLen = len(offer.Chunks) @@ -403,9 +401,6 @@ func (s *Syncer) Sync(ctx context.Context, peer swarm.Address, bin uint8, start // makeOffer tries to assemble an offer for a given requested interval. func (s *Syncer) makeOffer(ctx context.Context, rn pb.Get) (*pb.Offer, error) { - ctx, cancel := context.WithTimeout(ctx, makeOfferTimeout) - defer cancel() - addrs, top, err := s.collectAddrs(ctx, uint8(rn.Bin), rn.Start) if err != nil { return nil, err @@ -430,8 +425,6 @@ type collectAddrsResult struct { // After the arrival of the first chunk, the subsequent chunks have a limited amount of time to arrive, // after which the function returns the collected slice of chunks. func (s *Syncer) collectAddrs(ctx context.Context, bin uint8, start uint64) ([]*storer.BinC, uint64, error) { - loggerV2 := s.logger.V(2).Register() - v, _, err := s.intervalsSF.Do(ctx, sfKey(bin, start), func(ctx context.Context) (*collectAddrsResult, error) { var ( chs []*storer.BinC @@ -476,7 +469,7 @@ func (s *Syncer) collectAddrs(ctx context.Context, bin uint8, start uint64) ([]* case <-ctx.Done(): return nil, ctx.Err() case <-timerC: - loggerV2.Debug("batch timeout timer triggered") + s.logger.Debug("batch timeout timer triggered") // return batch if new chunks are not received after some time break LOOP } @@ -518,17 +511,14 @@ func (s *Syncer) processWant(ctx context.Context, o *pb.Offer, w *pb.Want) ([]sw } func (s *Syncer) GetCursors(ctx context.Context, peer swarm.Address) (retr []uint64, epoch uint64, err error) { - loggerV2 := s.logger.V(2).Register() - stream, err := s.streamer.NewStream(ctx, peer, nil, protocolName, protocolVersion, cursorStreamName) if err != nil { return nil, 0, fmt.Errorf("new stream: %w", err) } - loggerV2.Debug("getting cursors from peer", "peer_address", peer) + s.logger.Debug("getting cursors from peer", "peer_address", peer) defer func() { if err != nil { _ = stream.Reset() - loggerV2.Debug("error getting cursors from peer", "peer_address", peer, "error", err) } else { stream.FullClose() } @@ -549,14 +539,11 @@ func (s *Syncer) GetCursors(ctx context.Context, peer swarm.Address) (retr []uin } func (s *Syncer) cursorHandler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (err error) { - loggerV2 := s.logger.V(2).Register() - w, r := protobuf.NewWriterAndReader(stream) - loggerV2.Debug("peer wants cursors", "peer_address", p.Address) + s.logger.Debug("peer wants cursors", "peer_address", p.Address) defer func() { if err != nil { _ = stream.Reset() - loggerV2.Debug("error getting cursors for peer", "peer_address", p.Address, "error", err) } else { _ = stream.FullClose() } diff --git a/pkg/pushsync/main_test.go b/pkg/pushsync/main_test.go index 1364235fc42..cfd84a04c51 100644 --- a/pkg/pushsync/main_test.go +++ b/pkg/pushsync/main_test.go @@ -11,5 +11,5 @@ import ( ) func TestMain(m *testing.M) { - goleak.VerifyTestMain(m) + goleak.VerifyTestMain(m, goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start")) } diff --git a/pkg/pushsync/pushsync.go b/pkg/pushsync/pushsync.go index 715680430cf..05c4aef3d41 100644 --- a/pkg/pushsync/pushsync.go +++ b/pkg/pushsync/pushsync.go @@ -186,7 +186,10 @@ func (ps *PushSync) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) ps.metrics.TotalHandlerTime.WithLabelValues("failure").Observe(time.Since(now).Seconds()) ps.metrics.TotalHandlerErrors.Inc() if !attemptedWrite { - _ = w.WriteMsgWithContext(ctx, &pb.Receipt{Err: err.Error()}) + if writeErr := w.WriteMsgWithContext(ctx, &pb.Receipt{Err: err.Error()}); writeErr == nil { + _ = stream.FullClose() + return + } } _ = stream.Reset() } else { diff --git a/pkg/pushsync/pushsync_integration_test.go b/pkg/pushsync/pushsync_integration_test.go new file mode 100644 index 00000000000..e9b2fa30f11 --- /dev/null +++ b/pkg/pushsync/pushsync_integration_test.go @@ -0,0 +1,201 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pushsync_test + +import ( + "context" + "crypto/ecdsa" + "encoding/json" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + accountingmock "github.com/ethersphere/bee/v2/pkg/accounting/mock" + "github.com/ethersphere/bee/v2/pkg/crypto" + "github.com/ethersphere/bee/v2/pkg/log" + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/libp2ptest" + postagetesting "github.com/ethersphere/bee/v2/pkg/postage/testing" + pricermock "github.com/ethersphere/bee/v2/pkg/pricer/mock" + "github.com/ethersphere/bee/v2/pkg/pushsync" + "github.com/ethersphere/bee/v2/pkg/soc" + stabilizationmock "github.com/ethersphere/bee/v2/pkg/stabilization/mock" + "github.com/ethersphere/bee/v2/pkg/storage" + "github.com/ethersphere/bee/v2/pkg/storage/inmemchunkstore" + testingc "github.com/ethersphere/bee/v2/pkg/storage/testing" + "github.com/ethersphere/bee/v2/pkg/swarm" + topologymock "github.com/ethersphere/bee/v2/pkg/topology/mock" +) + +// TestPushSyncIntegration is a regression test for the fix of missing +// FullClose on pushsync streams. +func TestPushSyncIntegration(t *testing.T) { + // Capture logs to check for errors + var logMessages libp2ptest.SafeBuffer + + // Enable debug logging + logger := log.NewLogger("test", + log.WithVerbosity(log.VerbosityDebug), + log.WithJSONOutput(), + log.WithSink(&logMessages), + ) + + // Create two libp2p services + server, serverAddr := libp2ptest.NewLibp2pService(t, 1, logger.WithValues("libp2p", "server").Build()) + client, clientAddr := libp2ptest.NewLibp2pService(t, 1, logger.WithValues("libp2p", "client").Build()) + + // Server setup + serverStorer := &testIntegrationStorer{ChunkStore: inmemchunkstore.New()} + serverSigner := crypto.NewDefaultSigner(mustGenerateKey(t)) + + serverPushSync := pushsync.New( + serverAddr, + 1, + common.HexToHash("0x1").Bytes(), + server, // Use libp2p service as streamer + serverStorer, + func() (uint8, error) { return 0, nil }, + topologymock.NewTopologyDriver(), // No peers needed for server in this test + true, + func(swarm.Chunk) {}, // unwrap + func(*soc.SOC) {}, // gsocHandler + func(c swarm.Chunk) (swarm.Chunk, error) { + return c.WithStamp(postagetesting.MustNewValidStamp(serverSigner, c.Address())), nil + }, + logger.WithValues("pushsync", "server").Build(), + accountingmock.NewAccounting(), + pricermock.NewMockService(10, 10), + serverSigner, + nil, + stabilizationmock.NewSubscriber(true), + 0, + ) + t.Cleanup(func() { serverPushSync.Close() }) + + // Register pushsync protocol on server + if err := server.AddProtocol(serverPushSync.Protocol()); err != nil { + t.Fatal(err) + } + + // Client setup + clientStorer := &testIntegrationStorer{ChunkStore: inmemchunkstore.New()} + clientSigner := crypto.NewDefaultSigner(mustGenerateKey(t)) + + // Client needs to know server is the closest peer + clientTopology := topologymock.NewTopologyDriver(topologymock.WithPeers(serverAddr)) + + clientPushSync := pushsync.New( + clientAddr, + 1, + common.HexToHash("0x1").Bytes(), + client, // Use libp2p service as streamer + clientStorer, + func() (uint8, error) { return 0, nil }, + clientTopology, + true, + func(swarm.Chunk) {}, // unwrap + func(*soc.SOC) {}, // gsocHandler + func(c swarm.Chunk) (swarm.Chunk, error) { + return c.WithStamp(postagetesting.MustNewValidStamp(clientSigner, c.Address())), nil + }, + logger.WithValues("pushsync", "client").Build(), + accountingmock.NewAccounting(), + pricermock.NewMockService(10, 10), + clientSigner, + nil, + stabilizationmock.NewSubscriber(true), + 0, + ) + t.Cleanup(func() { clientPushSync.Close() }) + + // Register pushsync protocol on client + if err := client.AddProtocol(clientPushSync.Protocol()); err != nil { + t.Fatal(err) + } + + // Connect client to server + serverAddrs, err := server.Addresses() + if err != nil { + t.Fatal(err) + } + + _, err = client.Connect(context.Background(), serverAddrs) + if err != nil { + t.Fatal(err) + } + + // Push chunk + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Generate a chunk that is closer to the server than the client + var chunk swarm.Chunk + for { + chunk = testingc.GenerateTestRandomChunk() + // Check if chunk is closer to server + if swarm.Proximity(serverAddr.Bytes(), chunk.Address().Bytes()) > swarm.Proximity(clientAddr.Bytes(), chunk.Address().Bytes()) { + break + } + } + + _, err = clientPushSync.PushChunkToClosest(ctx, chunk) + if err != nil { + t.Fatal(err) + } + + // Verify chunk is stored on server + has, err := serverStorer.Has(ctx, chunk.Address()) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatal("chunk not found on server") + } + + // Validate that streams are properly closed by the pushsync service + // by checking for "stream reset" log entries + streamResetLogLine := "" + for line := range strings.SplitSeq(logMessages.String(), "\n") { + if line == "" { + continue + } + var entry map[string]any + if err := json.Unmarshal([]byte(line), &entry); err != nil { + t.Fatalf("failed to unmarshal log entry: %v", err) + } + errorString, ok := entry["error"].(string) + if !ok { + continue + } + if strings.Contains(errorString, "stream reset") { + streamResetLogLine = line + break + } + } + if streamResetLogLine != "" { + t.Errorf("found stream reset log line: %s", streamResetLogLine) + } +} + +type testIntegrationStorer struct { + storage.ChunkStore +} + +func (t *testIntegrationStorer) Report(context.Context, swarm.Chunk, storage.ChunkState) error { + return nil +} + +func (t *testIntegrationStorer) ReservePutter() storage.Putter { + return t.ChunkStore +} + +func mustGenerateKey(t *testing.T) *ecdsa.PrivateKey { + t.Helper() + k, err := crypto.GenerateSecp256k1Key() + if err != nil { + t.Fatal(err) + } + return k +} diff --git a/pkg/retrieval/main_test.go b/pkg/retrieval/main_test.go index 8be3983b65d..532dcc95bcb 100644 --- a/pkg/retrieval/main_test.go +++ b/pkg/retrieval/main_test.go @@ -16,5 +16,6 @@ func TestMain(m *testing.M) { // pkg/p2p package has some leak issues, we ignore them here as they are not in current scope goleak.IgnoreTopFunction("github.com/ethersphere/bee/v2/pkg/p2p/protobuf.Reader.ReadMsgWithContext"), goleak.IgnoreTopFunction("github.com/ethersphere/bee/v2/pkg/p2p/streamtest.(*record).Read"), + goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), ) } diff --git a/pkg/retrieval/retrieval.go b/pkg/retrieval/retrieval.go index 2fce97be5a2..f1e5f5193b7 100644 --- a/pkg/retrieval/retrieval.go +++ b/pkg/retrieval/retrieval.go @@ -431,7 +431,10 @@ func (s *Service) handler(p2pctx context.Context, p p2p.Peer, stream p2p.Stream) defer func() { if err != nil { if !attemptedWrite { - _ = w.WriteMsgWithContext(ctx, &pb.Delivery{Err: err.Error()}) + if writeErr := w.WriteMsgWithContext(ctx, &pb.Delivery{Err: err.Error()}); writeErr == nil { + _ = stream.FullClose() + return + } } _ = stream.Reset() } else { diff --git a/pkg/retrieval/retrieval_integration_test.go b/pkg/retrieval/retrieval_integration_test.go new file mode 100644 index 00000000000..de37e46018a --- /dev/null +++ b/pkg/retrieval/retrieval_integration_test.go @@ -0,0 +1,153 @@ +// Copyright 2025 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package retrieval_test + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "strings" + "testing" + "time" + + accountingmock "github.com/ethersphere/bee/v2/pkg/accounting/mock" + "github.com/ethersphere/bee/v2/pkg/log" + "github.com/ethersphere/bee/v2/pkg/p2p/libp2p/libp2ptest" + pricermock "github.com/ethersphere/bee/v2/pkg/pricer/mock" + "github.com/ethersphere/bee/v2/pkg/retrieval" + "github.com/ethersphere/bee/v2/pkg/storage/inmemchunkstore" + testingc "github.com/ethersphere/bee/v2/pkg/storage/testing" + "github.com/ethersphere/bee/v2/pkg/swarm" + "github.com/ethersphere/bee/v2/pkg/topology" + topologymock "github.com/ethersphere/bee/v2/pkg/topology/mock" +) + +// TestRetrievalIntegration is a regression test for the fix of missing +// FullClose on retrieval streams. +func TestRetrievalIntegration(t *testing.T) { + // Capture logs to check for errors + var logMessages libp2ptest.SafeBuffer + + // Enable debug logging + logger := log.NewLogger("test", + log.WithVerbosity(log.VerbosityDebug), + log.WithJSONOutput(), + log.WithSink(&logMessages), + ) + + // Create two libp2p services + server, serverAddr := libp2ptest.NewLibp2pService(t, 1, logger.WithValues("libp2p", "server").Build()) + client, clientAddr := libp2ptest.NewLibp2pService(t, 1, logger.WithValues("libp2p", "client").Build()) + + // Setup chunk + chunk := testingc.FixtureChunk("0033") + + // Server setup + serverStorer := &testStorer{ChunkStore: inmemchunkstore.New()} + err := serverStorer.Put(context.Background(), chunk) + if err != nil { + t.Fatal(err) + } + + serverRetrieval := retrieval.New( + serverAddr, + func() (uint8, error) { return swarm.MaxBins, nil }, + serverStorer, + server, // Use libp2p service as streamer + topologymock.NewTopologyDriver(), // No peers needed for server in this test + logger.WithValues("retrieval", "server").Build(), + accountingmock.NewAccounting(), + pricermock.NewMockService(10, 10), + nil, + false, + ) + t.Cleanup(func() { serverRetrieval.Close() }) + + // Register retrieval protocol on server + if err := server.AddProtocol(serverRetrieval.Protocol()); err != nil { + t.Fatal(err) + } + + // Client setup + clientStorer := &testStorer{ChunkStore: inmemchunkstore.New()} + + // Client needs to know server is the closest peer + clientTopology := topologymock.NewTopologyDriver(topologymock.WithPeers(serverAddr)) + + clientRetrieval := retrieval.New( + clientAddr, + func() (uint8, error) { return swarm.MaxBins, nil }, + clientStorer, + client, // Use libp2p service as streamer + clientTopology, + logger.WithValues("retrieval", "client").Build(), + accountingmock.NewAccounting(), + pricermock.NewMockService(10, 10), + nil, + false, + ) + t.Cleanup(func() { clientRetrieval.Close() }) + + // Register retrieval protocol on client + if err := client.AddProtocol(clientRetrieval.Protocol()); err != nil { + t.Fatal(err) + } + + // Connect client to server + serverAddrs, err := server.Addresses() + if err != nil { + t.Fatal(err) + } + + _, err = client.Connect(context.Background(), serverAddrs) + if err != nil { + t.Fatal(err) + } + + // Retrieve chunk + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + got, err := clientRetrieval.RetrieveChunk(ctx, chunk.Address(), swarm.ZeroAddress) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(got.Data(), chunk.Data()) { + t.Fatalf("request and response data not equal. got %s want %s", got.Data(), chunk.Data()) + } + + // Retrieve non-existing chunk + nonExistingChunk := testingc.GenerateTestRandomChunk() + _, err = clientRetrieval.RetrieveChunk(ctx, nonExistingChunk.Address(), swarm.ZeroAddress) + if !errors.Is(err, topology.ErrNotFound) { + t.Fatalf("expected error retrieving non-existing chunk, got %v", err) + } + + // Validate that streams are properly closed by the retrieval service + // by checking for "stream reset" log entries + streamResetLogLine := "" + for line := range strings.SplitSeq(logMessages.String(), "\n") { + if line == "" { + continue + } + var entry map[string]any + if err := json.Unmarshal([]byte(line), &entry); err != nil { + t.Fatalf("failed to unmarshal log entry: %v", err) + } + errorString, ok := entry["error"].(string) + if !ok { + continue + } + if strings.Contains(errorString, "stream reset") { + streamResetLogLine = line + break + } + } + if streamResetLogLine != "" { + t.Errorf("found stream reset log line: %s", streamResetLogLine) + } +} diff --git a/pkg/settlement/swap/swapprotocol/swapprotocol.go b/pkg/settlement/swap/swapprotocol/swapprotocol.go index 45715621208..5153a307bc3 100644 --- a/pkg/settlement/swap/swapprotocol/swapprotocol.go +++ b/pkg/settlement/swap/swapprotocol/swapprotocol.go @@ -126,7 +126,7 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e exchangeRate, deduction, err := swap.ParseSettlementResponseHeaders(responseHeaders) if err != nil { if !errors.Is(err, swap.ErrNoDeductionHeader) { - return err + return fmt.Errorf("parse settlement response headers: %w", err) } deduction = big.NewInt(0) } @@ -134,11 +134,15 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e var signedCheque *chequebook.SignedCheque err = json.Unmarshal(req.Cheque, &signedCheque) if err != nil { - return err + return fmt.Errorf("unmarshal cheque: %w", err) } // signature validation - return s.swap.ReceiveCheque(ctx, p.Address, signedCheque, exchangeRate, deduction) + if err := s.swap.ReceiveCheque(ctx, p.Address, signedCheque, exchangeRate, deduction); err != nil { + return fmt.Errorf("receive cheque: %w", err) + } + + return nil } func (s *Service) headler(receivedHeaders p2p.Headers, peerAddress swarm.Address) (returnHeaders p2p.Headers) { @@ -163,14 +167,12 @@ func (s *Service) headler(receivedHeaders p2p.Headers, peerAddress swarm.Address // InitiateCheque attempts to send a cheque to a peer. func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiary common.Address, amount *big.Int, issue IssueFunc) (balance *big.Int, err error) { - loggerV1 := s.logger.V(1).Register() - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() stream, err := s.streamer.NewStream(ctx, peer, nil, protocolName, protocolVersion, streamName) if err != nil { - return nil, err + return nil, fmt.Errorf("new stream: %w", err) } defer func() { if err != nil { @@ -185,7 +187,7 @@ func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiar exchangeRate, deduction, err := swap.ParseSettlementResponseHeaders(returnedHeaders) if err != nil { if !errors.Is(err, swap.ErrNoDeductionHeader) { - return nil, err + return nil, fmt.Errorf("parse settlement response headers: %w", err) } deduction = big.NewInt(0) } @@ -195,7 +197,7 @@ func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiar // get whether peer have deducted in the past checkPeer, err := s.swap.GetDeductionByPeer(peer) if err != nil { - return nil, err + return nil, fmt.Errorf("get deduction by peer: %w", err) } // if peer is not entitled for deduction but sent non zero deduction value, return with error @@ -206,7 +208,7 @@ func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiar // get current global exchangeRate rate and deduction checkExchangeRate, checkDeduction, err := s.priceOracle.CurrentRates() if err != nil { - return nil, err + return nil, fmt.Errorf("get current rates: %w", err) } // exchangeRate rates should match @@ -232,7 +234,7 @@ func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiar } // sending cheque - loggerV1.Debug("sending cheque message to peer", "peer_address", peer, "cheque", cheque) + s.logger.Debug("sending cheque message to peer", "peer_address", peer, "cheque", cheque) w := protobuf.NewWriter(stream) return w.WriteMsgWithContext(ctx, &pb.EmitCheque{ @@ -241,13 +243,13 @@ func (s *Service) EmitCheque(ctx context.Context, peer swarm.Address, beneficiar }) if err != nil { - return nil, err + return nil, fmt.Errorf("call issue function: %w", err) } if deduction.Cmp(big.NewInt(0)) != 0 { err = s.swap.AddDeductionByPeer(peer) if err != nil { - return nil, err + return nil, fmt.Errorf("add deduction for peer: %w", err) } } diff --git a/pkg/topology/kademlia/kademlia.go b/pkg/topology/kademlia/kademlia.go index 4761b15519a..b5bff41fc9a 100644 --- a/pkg/topology/kademlia/kademlia.go +++ b/pkg/topology/kademlia/kademlia.go @@ -1115,8 +1115,17 @@ func (k *Kad) AnnounceTo(ctx context.Context, addressee, peer swarm.Address, ful // This does not guarantee that a connection will immediately // be made to the peer. func (k *Kad) AddPeers(addrs ...swarm.Address) { - k.knownPeers.Add(addrs...) - k.notifyManageLoop() + toAdd := make([]swarm.Address, 0, len(addrs)) + for _, addr := range addrs { + if !addr.Equal(k.base) { + toAdd = append(toAdd, addr) + } + } + + if len(toAdd) > 0 { + k.knownPeers.Add(toAdd...) + k.notifyManageLoop() + } } func (k *Kad) Pick(peer p2p.Peer) bool { diff --git a/pkg/topology/kademlia/kademlia_test.go b/pkg/topology/kademlia/kademlia_test.go index 4d534ddade8..6750ebe2284 100644 --- a/pkg/topology/kademlia/kademlia_test.go +++ b/pkg/topology/kademlia/kademlia_test.go @@ -2253,3 +2253,72 @@ func generateMultipleUnderlays(t *testing.T, n int, baseUnderlay string) []ma.Mu } return underlays } + +// TestAddPeersSkipsSelf verifies that AddPeers does not add self address +// to the known peers list, preventing self-connection attempts. +func TestAddPeersSkipsSelf(t *testing.T) { + t.Parallel() + + var ( + conns int32 + base, kad, ab, _, signer = newTestKademlia(t, &conns, nil, kademlia.Options{ + ExcludeFunc: defaultExcludeFunc, + }) + ) + + if err := kad.Start(context.Background()); err != nil { + t.Fatal(err) + } + testutil.CleanupCloser(t, kad) + + // Add some regular peers first + peer1 := swarm.RandAddressAt(t, base, 1) + peer2 := swarm.RandAddressAt(t, base, 2) + + addOne(t, signer, kad, ab, peer1) + addOne(t, signer, kad, ab, peer2) + + waitCounter(t, &conns, 2) + + // Now try to add self address along with another peer + peer3 := swarm.RandAddressAt(t, base, 3) + + // Prepare address for peer3 + multiaddr, err := ma.NewMultiaddr(underlayBase + peer3.String()) + if err != nil { + t.Fatal(err) + } + bzzAddr, err := bzz.NewAddress(signer, []ma.Multiaddr{multiaddr}, peer3, 0, nil) + if err != nil { + t.Fatal(err) + } + if err := ab.Put(peer3, *bzzAddr); err != nil { + t.Fatal(err) + } + + // Try to add self (base) and peer3 together + kad.AddPeers(base, peer3) + + // Only peer3 should result in a connection attempt, not base + waitCounter(t, &conns, 1) + + // Verify we have exactly 3 connected peers (peer1, peer2, peer3), not 4 + waitPeers(t, kad, 3) + + // Verify base is not in the connected peers list + foundSelf := false + err = kad.EachConnectedPeer(func(addr swarm.Address, _ uint8) (bool, bool, error) { + if addr.Equal(base) { + foundSelf = true + return true, false, nil + } + return false, false, nil + }, topology.Select{}) + if err != nil { + t.Fatal(err) + } + + if foundSelf { + t.Fatal("self address should not be in connected peers") + } +}