From d1cae942165f4871f8051e266722c0ca717780cb Mon Sep 17 00:00:00 2001 From: Cassie Heart Date: Fri, 7 Jun 2024 06:25:43 +0000 Subject: [PATCH] feat: go 1.22 support --- client/go.mod | 12 +- client/go.sum | 41 +- go-libp2p-blossomsub/blossomsub.go | 286 +++-- go-libp2p-blossomsub/comm.go | 3 + go-libp2p-blossomsub/go.mod | 5 +- go-libp2p-blossomsub/notify.go | 4 +- go-libp2p-blossomsub/peer_gater.go | 2 +- go-libp2p-blossomsub/score.go | 2 +- go-libp2p-gostream/go.mod | 3 +- go-libp2p/.github/ISSUE_TEMPLATE/config.yml | 8 + go-libp2p/.github/workflows/automerge.yml | 11 - go-libp2p/.github/workflows/go-check.yml | 81 +- go-libp2p/.github/workflows/go-test.yml | 92 +- go-libp2p/.github/workflows/interop-test.yml | 19 +- go-libp2p/.github/workflows/release-check.yml | 18 +- go-libp2p/.github/workflows/releaser.yml | 14 +- go-libp2p/.github/workflows/tagpush.yml | 14 +- go-libp2p/README.md | 12 +- go-libp2p/config/config.go | 295 +++-- go-libp2p/config/host.go | 30 + .../{quic_stateless_reset.go => quic.go} | 18 +- go-libp2p/core/connmgr/manager.go | 10 + go-libp2p/core/connmgr/null.go | 1 + go-libp2p/core/crypto/ecdsa.go | 3 +- go-libp2p/core/crypto/ecdsa_test.go | 2 +- go-libp2p/core/crypto/key.go | 47 - go-libp2p/core/crypto/key_test.go | 16 +- go-libp2p/core/crypto/key_to_stdlib.go | 18 +- go-libp2p/core/crypto/pb/crypto.pb.go | 1 - go-libp2p/core/crypto/rsa_go.go | 3 +- go-libp2p/core/crypto/rsa_test.go | 2 +- go-libp2p/core/crypto/secp256k1.go | 2 +- go-libp2p/core/crypto/secp256k1_test.go | 2 +- go-libp2p/core/event/identify.go | 31 +- go-libp2p/core/network/context.go | 38 +- go-libp2p/core/network/context_test.go | 4 +- go-libp2p/core/network/errors.go | 8 +- .../mocks/mock_conn_management_scope.go | 13 +- .../core/network/mocks/mock_peer_scope.go | 11 +- .../core/network/mocks/mock_protocol_scope.go | 11 +- .../network/mocks/mock_resource_manager.go | 21 +- .../network/mocks/mock_resource_scope_span.go | 11 +- .../mocks/mock_stream_management_scope.go | 15 +- go-libp2p/core/network/mocks/network.go | 12 +- go-libp2p/core/network/network.go | 15 +- go-libp2p/core/peer/addrinfo.go | 4 +- go-libp2p/core/peer/addrinfo_test.go | 12 +- go-libp2p/core/peer/peer.go | 16 - go-libp2p/core/peer/peer_serde.go | 4 +- go-libp2p/core/peerstore/peerstore.go | 3 +- go-libp2p/core/routing/routing.go | 2 +- go-libp2p/core/sec/security.go | 12 + go-libp2p/core/transport/transport.go | 45 + go-libp2p/dashboards/README.md | 14 + go-libp2p/dashboards/autonat/autonat.json | 2 +- go-libp2p/dashboards/docker-compose.base.yml | 1 + go-libp2p/dashboards/eventbus/eventbus.json | 2 +- go-libp2p/dashboards/holepunch/holepunch.json | 2 +- go-libp2p/dashboards/identify/identify.json | 2 +- go-libp2p/dashboards/relaysvc/relaysvc.json | 2 +- .../resource-manager/resource-manager.json | 2 +- go-libp2p/dashboards/swarm/swarm.json | 200 +++- go-libp2p/defaults.go | 4 +- go-libp2p/docs/flaky-tests.md | 2 +- go-libp2p/examples/README.md | 8 +- go-libp2p/examples/chat-with-mdns/README.md | 16 +- go-libp2p/examples/chat-with-mdns/main.go | 7 +- .../examples/chat-with-rendezvous/chat.go | 27 +- go-libp2p/examples/chat/chat.go | 2 +- go-libp2p/examples/chat/chat_test.go | 2 +- go-libp2p/examples/echo/README.md | 2 +- go-libp2p/examples/echo/main.go | 14 +- go-libp2p/examples/go.mod | 95 +- go-libp2p/examples/go.sum | 251 ++-- go-libp2p/examples/http-proxy/proxy.go | 2 +- .../ipfs-camp-2019/05-Discovery/main.go | 6 +- .../examples/ipfs-camp-2019/06-Pubsub/main.go | 6 +- .../ipfs-camp-2019/07-Messaging/main.go | 6 +- .../examples/ipfs-camp-2019/08-End/main.go | 6 +- go-libp2p/examples/ipfs-camp-2019/go.mod | 105 +- go-libp2p/examples/ipfs-camp-2019/go.sum | 273 +++-- go-libp2p/examples/libp2p-host/README.md | 2 +- go-libp2p/examples/multipro/pb/p2p.pb.go | 4 +- go-libp2p/examples/multipro/pb/p2p.proto | 4 +- go-libp2p/examples/pubsub/README.md | 3 +- .../pubsub/basic-chat-with-rendezvous/go.mod | 104 +- .../pubsub/basic-chat-with-rendezvous/go.sum | 267 ++--- .../pubsub/basic-chat-with-rendezvous/main.go | 4 +- go-libp2p/examples/pubsub/chat/README.md | 2 +- go-libp2p/examples/pubsub/chat/chatroom.go | 2 +- go-libp2p/examples/pubsub/chat/go.mod | 89 +- go-libp2p/examples/pubsub/chat/go.sum | 216 ++-- go-libp2p/examples/pubsub/chat/main.go | 6 +- go-libp2p/examples/relay/README.md | 15 + go-libp2p/examples/relay/main.go | 2 +- go-libp2p/examples/routed-echo/main.go | 4 +- go-libp2p/go.mod | 113 +- go-libp2p/go.sum | 653 ++++------- go-libp2p/leaky_tests/README.md | 1 + go-libp2p/leaky_tests/leaky_test.go | 19 + go-libp2p/libp2p.go | 4 +- go-libp2p/libp2p_test.go | 151 ++- go-libp2p/options.go | 16 +- .../p2p/discovery/backoff/backoffcache.go | 8 - .../discovery/backoff/backoffcache_test.go | 8 + go-libp2p/p2p/host/autonat/autonat.go | 4 +- go-libp2p/p2p/host/autonat/svc.go | 15 +- go-libp2p/p2p/host/autonat/svc_test.go | 2 +- go-libp2p/p2p/host/autorelay/addrsplosion.go | 2 +- .../p2p/host/autorelay/addrsplosion_test.go | 16 +- go-libp2p/p2p/host/autorelay/host.go | 23 - go-libp2p/p2p/host/autorelay/metrics.go | 4 +- go-libp2p/p2p/host/autorelay/relay_finder.go | 4 +- go-libp2p/p2p/host/basic/basic_host.go | 123 +- go-libp2p/p2p/host/basic/basic_host_test.go | 68 +- go-libp2p/p2p/host/basic/mock_nat_test.go | 13 +- go-libp2p/p2p/host/basic/mocks.go | 2 +- go-libp2p/p2p/host/basic/natmgr.go | 2 +- go-libp2p/p2p/host/basic/natmgr_test.go | 2 +- go-libp2p/p2p/host/blank/blank.go | 9 +- .../p2p/host/peerstore/pstoreds/addr_book.go | 16 +- .../host/peerstore/pstoreds/addr_book_gc.go | 12 +- .../p2p/host/peerstore/pstoreds/deprecate.go | 5 + .../p2p/host/peerstore/pstoreds/keybook.go | 18 +- .../p2p/host/peerstore/pstoreds/protobook.go | 2 +- .../p2p/host/peerstore/pstoremem/addr_book.go | 2 +- .../p2p/host/peerstore/pstoremem/protobook.go | 2 +- .../host/peerstore/pstoremem/sorting_test.go | 2 +- .../host/peerstore/test/peerstore_suite.go | 10 +- go-libp2p/p2p/host/peerstore/test/utils.go | 2 +- .../host/pstoremanager/mock_peerstore_test.go | 81 +- .../p2p/host/pstoremanager/pstoremanager.go | 24 +- .../host/pstoremanager/pstoremanager_test.go | 11 +- go-libp2p/p2p/host/resource-manager/README.md | 6 +- .../p2p/host/resource-manager/conn_limiter.go | 288 +++++ .../resource-manager/conn_limiter_test.go | 214 ++++ .../host/resource-manager/docs/allowlist.md | 2 +- go-libp2p/p2p/host/resource-manager/extapi.go | 4 + .../p2p/host/resource-manager/limit_test.go | 5 +- go-libp2p/p2p/host/resource-manager/rcmgr.go | 82 +- .../p2p/host/resource-manager/rcmgr_test.go | 60 + go-libp2p/p2p/host/resource-manager/scope.go | 13 +- .../p2p/host/resource-manager/scope_test.go | 6 +- go-libp2p/p2p/host/routed/routed.go | 4 +- go-libp2p/p2p/http/example_test.go | 359 ++++++ go-libp2p/p2p/http/libp2phttp.go | 918 +++++++++++++++ go-libp2p/p2p/http/libp2phttp_test.go | 721 ++++++++++++ go-libp2p/p2p/http/options.go | 24 + go-libp2p/p2p/http/ping/ping.go | 67 ++ go-libp2p/p2p/metricshelper/conn.go | 2 +- go-libp2p/p2p/muxer/mplex/conn.go | 48 - go-libp2p/p2p/muxer/mplex/stream.go | 64 -- go-libp2p/p2p/muxer/mplex/transport.go | 28 - go-libp2p/p2p/muxer/mplex/transport_test.go | 52 - go-libp2p/p2p/net/connmgr/connmgr.go | 14 +- go-libp2p/p2p/net/connmgr/connmgr_test.go | 32 +- go-libp2p/p2p/net/connmgr/decay.go | 4 +- go-libp2p/p2p/net/connmgr/decay_test.go | 4 +- go-libp2p/p2p/net/gostream/addr.go | 14 + go-libp2p/p2p/net/gostream/conn.go | 43 + go-libp2p/p2p/net/gostream/gostream.go | 19 + go-libp2p/p2p/net/gostream/gostream_test.go | 141 +++ go-libp2p/p2p/net/gostream/listener.go | 71 ++ go-libp2p/p2p/net/mock/mock_test.go | 4 +- go-libp2p/p2p/net/nat/mock_nat_test.go | 11 +- go-libp2p/p2p/net/nat/nat_test.go | 4 +- go-libp2p/p2p/net/reuseport/dialer.go | 2 +- go-libp2p/p2p/net/reuseport/transport_test.go | 7 +- go-libp2p/p2p/net/swarm/addrs.go | 39 - .../p2p/net/swarm/black_hole_detector.go | 7 +- .../p2p/net/swarm/black_hole_detector_test.go | 52 +- .../net/swarm/connectedness_event_emitter.go | 143 +++ go-libp2p/p2p/net/swarm/dial_error.go | 25 +- go-libp2p/p2p/net/swarm/dial_error_test.go | 51 + go-libp2p/p2p/net/swarm/dial_ranker.go | 105 +- go-libp2p/p2p/net/swarm/dial_ranker_test.go | 97 +- go-libp2p/p2p/net/swarm/dial_sync.go | 46 +- go-libp2p/p2p/net/swarm/dial_test.go | 15 +- go-libp2p/p2p/net/swarm/dial_worker.go | 145 +-- go-libp2p/p2p/net/swarm/dial_worker_test.go | 81 +- go-libp2p/p2p/net/swarm/limiter.go | 18 +- go-libp2p/p2p/net/swarm/limiter_test.go | 20 +- go-libp2p/p2p/net/swarm/swarm.go | 237 ++-- go-libp2p/p2p/net/swarm/swarm_addr_test.go | 11 +- go-libp2p/p2p/net/swarm/swarm_conn.go | 26 +- go-libp2p/p2p/net/swarm/swarm_dial.go | 177 ++- go-libp2p/p2p/net/swarm/swarm_dial_test.go | 111 +- go-libp2p/p2p/net/swarm/swarm_event_test.go | 203 +++- go-libp2p/p2p/net/swarm/swarm_metrics.go | 26 +- go-libp2p/p2p/net/swarm/swarm_metrics_test.go | 6 +- go-libp2p/p2p/net/swarm/swarm_stream.go | 37 +- go-libp2p/p2p/net/swarm/swarm_test.go | 16 +- go-libp2p/p2p/net/swarm/testing/testing.go | 9 +- go-libp2p/p2p/net/swarm/util_test.go | 2 +- go-libp2p/p2p/net/upgrader/listener.go | 2 +- go-libp2p/p2p/net/upgrader/listener_test.go | 4 +- go-libp2p/p2p/net/upgrader/upgrader.go | 39 +- go-libp2p/p2p/net/upgrader/upgrader_test.go | 2 +- .../p2p/protocol/circuitv2/client/dial.go | 2 +- .../p2p/protocol/circuitv2/client/handlers.go | 4 +- .../protocol/circuitv2/client/transport.go | 1 + .../protocol/circuitv2/relay/constraints.go | 12 +- .../p2p/protocol/circuitv2/relay/relay.go | 7 +- .../protocol/circuitv2/relay/relay_test.go | 40 +- .../p2p/protocol/holepunch/holepunch_test.go | 12 +- .../p2p/protocol/holepunch/holepuncher.go | 2 +- .../holepunch/metrics_noalloc_test.go | 4 +- .../p2p/protocol/holepunch/metrics_test.go | 33 +- go-libp2p/p2p/protocol/holepunch/svc.go | 8 +- go-libp2p/p2p/protocol/identify/id.go | 223 +++- .../p2p/protocol/identify/id_glass_test.go | 33 + go-libp2p/p2p/protocol/identify/id_test.go | 258 +++-- .../p2p/protocol/identify/nat_emitter.go | 119 ++ go-libp2p/p2p/protocol/identify/obsaddr.go | 919 +++++++-------- .../protocol/identify/obsaddr_glass_test.go | 158 +-- .../p2p/protocol/identify/obsaddr_test.go | 1018 ++++++++++------- go-libp2p/p2p/protocol/identify/opts.go | 17 +- go-libp2p/p2p/protocol/ping/ping.go | 7 +- go-libp2p/p2p/security/noise/LICENSE.md | 229 ---- go-libp2p/p2p/security/noise/handshake.go | 14 +- .../p2p/security/noise/transport_test.go | 24 +- go-libp2p/p2p/security/tls/LICENSE.md | 7 - .../p2p/security/tls/cmd/tlsdiag/client.go | 4 +- .../p2p/security/tls/cmd/tlsdiag/server.go | 6 +- go-libp2p/p2p/security/tls/crypto.go | 18 +- go-libp2p/p2p/security/tls/crypto_test.go | 14 +- go-libp2p/p2p/security/tls/extension_test.go | 2 +- go-libp2p/p2p/security/tls/transport.go | 2 +- go-libp2p/p2p/security/tls/transport_test.go | 30 +- .../p2p/test/basichost/basic_host_test.go | 135 ++- go-libp2p/p2p/test/negotiation/muxer_test.go | 21 +- .../test/notifications/notification_test.go | 2 +- go-libp2p/p2p/test/quic/quic_test.go | 128 +-- go-libp2p/p2p/test/security/bench_test.go | 130 +++ go-libp2p/p2p/test/swarm/swarm_test.go | 245 ++++ go-libp2p/p2p/test/transport/deadline_test.go | 94 ++ go-libp2p/p2p/test/transport/gating_test.go | 41 +- .../transport/mock_connection_gater_test.go | 17 +- go-libp2p/p2p/test/transport/rcmgr_test.go | 11 +- .../p2p/test/transport/transport_test.go | 278 +++-- .../p2p/transport/quic/cmd/client/main.go | 63 +- go-libp2p/p2p/transport/quic/cmd/lib/lib.go | 129 +++ .../p2p/transport/quic/cmd/lib/lib_test.go | 30 + .../p2p/transport/quic/cmd/server/main.go | 71 +- go-libp2p/p2p/transport/quic/conn_test.go | 119 +- go-libp2p/p2p/transport/quic/listener.go | 3 - go-libp2p/p2p/transport/quic/listener_test.go | 41 +- .../quic/mock_connection_gater_test.go | 17 +- go-libp2p/p2p/transport/quic/transport.go | 4 +- .../p2p/transport/quic/transport_test.go | 16 +- go-libp2p/p2p/transport/quicreuse/config.go | 11 +- go-libp2p/p2p/transport/quicreuse/connmgr.go | 76 +- .../p2p/transport/quicreuse/connmgr_test.go | 22 +- go-libp2p/p2p/transport/quicreuse/listener.go | 12 +- go-libp2p/p2p/transport/quicreuse/options.go | 10 - .../p2p/transport/quicreuse/quic_multiaddr.go | 8 +- .../quicreuse/quic_multiaddr_test.go | 22 +- go-libp2p/p2p/transport/quicreuse/reuse.go | 33 +- .../p2p/transport/quicreuse/reuse_test.go | 36 +- go-libp2p/p2p/transport/quicreuse/tracer.go | 2 +- .../p2p/transport/quicreuse/tracer_metrics.go | 372 ------ .../p2p/transport/quicreuse/tracer_test.go | 8 +- go-libp2p/p2p/transport/tcp/metrics.go | 2 +- .../p2p/transport/tcp/metrics_general.go | 2 +- .../{metrics_windows.go => metrics_none.go} | 4 +- go-libp2p/p2p/transport/tcp/tcp.go | 16 +- go-libp2p/p2p/transport/tcp/tcp_test.go | 51 +- go-libp2p/p2p/transport/webrtc/connection.go | 255 +++++ go-libp2p/p2p/transport/webrtc/fingerprint.go | 53 + go-libp2p/p2p/transport/webrtc/hex.go | 70 ++ go-libp2p/p2p/transport/webrtc/hex_test.go | 132 +++ go-libp2p/p2p/transport/webrtc/listener.go | 350 ++++++ go-libp2p/p2p/transport/webrtc/logger.go | 58 + go-libp2p/p2p/transport/webrtc/message.go | 3 + go-libp2p/p2p/transport/webrtc/pb/generate.go | 3 + .../p2p/transport/webrtc/pb/message.pb.go | 231 ++++ .../p2p/transport/webrtc/pb/message.proto | 24 + go-libp2p/p2p/transport/webrtc/sdp.go | 143 +++ go-libp2p/p2p/transport/webrtc/sdp_test.go | 101 ++ go-libp2p/p2p/transport/webrtc/stream.go | 281 +++++ go-libp2p/p2p/transport/webrtc/stream_read.go | 113 ++ go-libp2p/p2p/transport/webrtc/stream_test.go | 563 +++++++++ .../p2p/transport/webrtc/stream_write.go | 157 +++ go-libp2p/p2p/transport/webrtc/transport.go | 651 +++++++++++ .../p2p/transport/webrtc/transport_test.go | 862 ++++++++++++++ go-libp2p/p2p/transport/webrtc/udpmux/mux.go | 298 +++++ .../p2p/transport/webrtc/udpmux/mux_test.go | 248 ++++ .../webrtc/udpmux/muxed_connection.go | 112 ++ .../p2p/transport/websocket/addrs_test.go | 8 +- .../p2p/transport/websocket/websocket.go | 4 +- .../p2p/transport/websocket/websocket_test.go | 5 +- .../webtransport/cert_manager_test.go | 2 +- .../p2p/transport/webtransport/listener.go | 9 + .../mock_connection_gater_test.go | 17 +- .../p2p/transport/webtransport/multiaddr.go | 28 +- .../transport/webtransport/multiaddr_test.go | 1 + .../p2p/transport/webtransport/transport.go | 17 +- .../transport/webtransport/transport_test.go | 12 +- go-libp2p/package-list.json | 82 -- go-libp2p/test-plans/PingDockerfile | 4 +- go-libp2p/test-plans/README.md | 8 +- go-libp2p/test-plans/cmd/ping/main.go | 17 +- go-libp2p/test-plans/go.mod | 98 +- go-libp2p/test-plans/go.sum | 285 +++-- go-libp2p/test-plans/ping-version.json | 7 +- go-libp2p/tools.go | 2 +- go-libp2p/version.json | 2 +- node/config/config.go | 63 +- node/go.mod | 83 +- node/go.sum | 234 ++-- node/p2p/blossomsub.go | 6 +- 311 files changed, 15039 insertions(+), 5860 deletions(-) create mode 100644 go-libp2p/.github/ISSUE_TEMPLATE/config.yml delete mode 100644 go-libp2p/.github/workflows/automerge.yml create mode 100644 go-libp2p/config/host.go rename go-libp2p/config/{quic_stateless_reset.go => quic.go} (53%) create mode 100644 go-libp2p/examples/relay/README.md create mode 100644 go-libp2p/leaky_tests/README.md create mode 100644 go-libp2p/leaky_tests/leaky_test.go delete mode 100644 go-libp2p/p2p/host/autorelay/host.go create mode 100644 go-libp2p/p2p/host/peerstore/pstoreds/deprecate.go create mode 100644 go-libp2p/p2p/host/resource-manager/conn_limiter.go create mode 100644 go-libp2p/p2p/host/resource-manager/conn_limiter_test.go create mode 100644 go-libp2p/p2p/http/example_test.go create mode 100644 go-libp2p/p2p/http/libp2phttp.go create mode 100644 go-libp2p/p2p/http/libp2phttp_test.go create mode 100644 go-libp2p/p2p/http/options.go create mode 100644 go-libp2p/p2p/http/ping/ping.go delete mode 100644 go-libp2p/p2p/muxer/mplex/conn.go delete mode 100644 go-libp2p/p2p/muxer/mplex/stream.go delete mode 100644 go-libp2p/p2p/muxer/mplex/transport.go delete mode 100644 go-libp2p/p2p/muxer/mplex/transport_test.go create mode 100644 go-libp2p/p2p/net/gostream/addr.go create mode 100644 go-libp2p/p2p/net/gostream/conn.go create mode 100644 go-libp2p/p2p/net/gostream/gostream.go create mode 100644 go-libp2p/p2p/net/gostream/gostream_test.go create mode 100644 go-libp2p/p2p/net/gostream/listener.go delete mode 100644 go-libp2p/p2p/net/swarm/addrs.go create mode 100644 go-libp2p/p2p/net/swarm/connectedness_event_emitter.go create mode 100644 go-libp2p/p2p/net/swarm/dial_error_test.go create mode 100644 go-libp2p/p2p/protocol/identify/nat_emitter.go delete mode 100644 go-libp2p/p2p/security/noise/LICENSE.md delete mode 100644 go-libp2p/p2p/security/tls/LICENSE.md create mode 100644 go-libp2p/p2p/test/security/bench_test.go create mode 100644 go-libp2p/p2p/test/swarm/swarm_test.go create mode 100644 go-libp2p/p2p/test/transport/deadline_test.go create mode 100644 go-libp2p/p2p/transport/quic/cmd/lib/lib.go create mode 100644 go-libp2p/p2p/transport/quic/cmd/lib/lib_test.go delete mode 100644 go-libp2p/p2p/transport/quicreuse/tracer_metrics.go rename go-libp2p/p2p/transport/tcp/{metrics_windows.go => metrics_none.go} (68%) create mode 100644 go-libp2p/p2p/transport/webrtc/connection.go create mode 100644 go-libp2p/p2p/transport/webrtc/fingerprint.go create mode 100644 go-libp2p/p2p/transport/webrtc/hex.go create mode 100644 go-libp2p/p2p/transport/webrtc/hex_test.go create mode 100644 go-libp2p/p2p/transport/webrtc/listener.go create mode 100644 go-libp2p/p2p/transport/webrtc/logger.go create mode 100644 go-libp2p/p2p/transport/webrtc/message.go create mode 100644 go-libp2p/p2p/transport/webrtc/pb/generate.go create mode 100644 go-libp2p/p2p/transport/webrtc/pb/message.pb.go create mode 100644 go-libp2p/p2p/transport/webrtc/pb/message.proto create mode 100644 go-libp2p/p2p/transport/webrtc/sdp.go create mode 100644 go-libp2p/p2p/transport/webrtc/sdp_test.go create mode 100644 go-libp2p/p2p/transport/webrtc/stream.go create mode 100644 go-libp2p/p2p/transport/webrtc/stream_read.go create mode 100644 go-libp2p/p2p/transport/webrtc/stream_test.go create mode 100644 go-libp2p/p2p/transport/webrtc/stream_write.go create mode 100644 go-libp2p/p2p/transport/webrtc/transport.go create mode 100644 go-libp2p/p2p/transport/webrtc/transport_test.go create mode 100644 go-libp2p/p2p/transport/webrtc/udpmux/mux.go create mode 100644 go-libp2p/p2p/transport/webrtc/udpmux/mux_test.go create mode 100644 go-libp2p/p2p/transport/webrtc/udpmux/muxed_connection.go delete mode 100644 go-libp2p/package-list.json diff --git a/client/go.mod b/client/go.mod index feeaf2c..855be36 100644 --- a/client/go.mod +++ b/client/go.mod @@ -1,6 +1,8 @@ module source.quilibrium.com/quilibrium/monorepo/client -go 1.20 +go 1.21 + +toolchain go1.22.1 replace github.com/libp2p/go-libp2p => ../go-libp2p @@ -11,7 +13,7 @@ replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptolog require ( github.com/iden3/go-iden3-crypto v0.0.15 github.com/mr-tron/base58 v1.2.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 ) require ( @@ -20,8 +22,6 @@ require ( github.com/bwesterb/go-ristretto v1.2.3 // indirect github.com/consensys/gnark-crypto v0.5.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.24.0 // indirect @@ -33,7 +33,7 @@ require ( require ( github.com/cloudflare/circl v1.3.8 - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/libp2p/go-libp2p v0.33.2 github.com/pkg/errors v0.9.1 @@ -41,6 +41,6 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 // indirect go.uber.org/zap v1.27.0 - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect source.quilibrium.com/quilibrium/monorepo/node v1.14.17 ) diff --git a/client/go.sum b/client/go.sum index 69e7b3f..95289c6 100644 --- a/client/go.sum +++ b/client/go.sum @@ -26,40 +26,53 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 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/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= 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/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= -github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -69,17 +82,20 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/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.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -91,7 +107,8 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -102,7 +119,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -110,10 +126,12 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -122,4 +140,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/go-libp2p-blossomsub/blossomsub.go b/go-libp2p-blossomsub/blossomsub.go index 9005a1e..bb2824b 100644 --- a/go-libp2p-blossomsub/blossomsub.go +++ b/go-libp2p-blossomsub/blossomsub.go @@ -1,6 +1,7 @@ package blossomsub import ( + "bytes" "context" "fmt" "math/rand" @@ -9,12 +10,14 @@ import ( pb "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/record" + "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" ) const ( @@ -26,7 +29,7 @@ const ( var ( BlossomSubD = 6 BlossomSubDlo = 5 - BlossomSubDhi = 10 + BlossomSubDhi = 12 BlossomSubDscore = 4 BlossomSubDout = 2 BlossomSubHistoryLength = 5 @@ -219,6 +222,7 @@ func NewBlossomSubRouter(h host.Host, params BlossomSubParams) *BlossomSubRouter lastpub: make(map[string]int64), gossip: make(map[peer.ID][]*pb.ControlIHave), control: make(map[peer.ID]*pb.ControlMessage), + cab: pstoremem.NewAddrBook(), backoff: make(map[string]map[peer.ID]time.Time), peerhave: make(map[peer.ID]int), iasked: make(map[peer.ID]int), @@ -247,6 +251,7 @@ func DefaultBlossomSubRouter(h host.Host) *BlossomSubRouter { iasked: make(map[peer.ID]int), outbound: make(map[peer.ID]bool), connect: make(chan connectInfo, params.MaxPendingConnections), + cab: pstoremem.NewAddrBook(), mcache: NewMessageCache(params.HistoryGossip, params.HistoryLength), protos: BlossomSubDefaultProtocols, feature: BlossomSubDefaultFeatures, @@ -447,6 +452,7 @@ type BlossomSubRouter struct { outbound map[peer.ID]bool // connection direction cache, marks peers with outbound connections backoff map[string]map[peer.ID]time.Time // prune backoff connect chan connectInfo // px connection requests + cab peerstore.AddrBook protos []protocol.ID feature BlossomSubFeatureTest @@ -525,6 +531,9 @@ func (bs *BlossomSubRouter) Attach(p *PubSub) { go bs.connector() } + // Manage our address book from events emitted by libp2p + go bs.manageAddrBook() + // connect to direct peers if len(bs.direct) > 0 { go func() { @@ -538,6 +547,46 @@ func (bs *BlossomSubRouter) Attach(p *PubSub) { } } +func (bs *BlossomSubRouter) manageAddrBook() { + sub, err := bs.p.host.EventBus().Subscribe([]interface{}{ + &event.EvtPeerIdentificationCompleted{}, + &event.EvtPeerConnectednessChanged{}, + }) + if err != nil { + log.Errorf("failed to subscribe to peer identification events: %v", err) + return + } + defer sub.Close() + + for { + select { + case <-bs.p.ctx.Done(): + return + case ev := <-sub.Out(): + switch ev := ev.(type) { + case event.EvtPeerIdentificationCompleted: + if ev.SignedPeerRecord != nil { + cab, ok := peerstore.GetCertifiedAddrBook(bs.cab) + if ok { + ttl := peerstore.RecentlyConnectedAddrTTL + if bs.p.host.Network().Connectedness(ev.Peer) == network.Connected { + ttl = peerstore.ConnectedAddrTTL + } + _, err := cab.ConsumePeerRecord(ev.SignedPeerRecord, ttl) + if err != nil { + log.Warnf("failed to consume signed peer record: %v", err) + } + } + } + case event.EvtPeerConnectednessChanged: + if ev.Connectedness != network.Connected { + bs.cab.UpdateAddrs(ev.Peer, peerstore.ConnectedAddrTTL, peerstore.RecentlyConnectedAddrTTL) + } + } + } + } +} + func (bs *BlossomSubRouter) AddPeer(p peer.ID, proto protocol.ID) { log.Debugf("PEERUP: Add new peer %s using %s", p, proto) bs.tracer.AddPeer(p, proto) @@ -550,7 +599,7 @@ loop: for _, c := range conns { stat := c.Stat() - if stat.Transient { + if stat.Limited { continue } @@ -968,7 +1017,7 @@ func (bs *BlossomSubRouter) connector() { } log.Debugf("connecting to %s", ci.p) - cab, ok := peerstore.GetCertifiedAddrBook(bs.p.host.Peerstore()) + cab, ok := peerstore.GetCertifiedAddrBook(bs.cab) if ok && ci.spr != nil { _, err := cab.ConsumePeerRecord(ci.spr, peerstore.TempAddrTTL) if err != nil { @@ -977,7 +1026,7 @@ func (bs *BlossomSubRouter) connector() { } ctx, cancel := context.WithTimeout(bs.p.ctx, bs.params.ConnectionTimeout) - err := bs.p.host.Connect(ctx, peer.AddrInfo{ID: ci.p}) + err := bs.p.host.Connect(ctx, peer.AddrInfo{ID: ci.p, Addrs: bs.cab.Addrs(ci.p)}) cancel() if err != nil { log.Debugf("error connecting to %s: %s", ci.p, err) @@ -1188,20 +1237,20 @@ func (bs *BlossomSubRouter) sendRPC(p peer.ID, out *RPC) { return } - // If we're too big, fragment into multiple RPCs and send each sequentially - outRPCs, err := fragmentRPC(out, bs.p.maxMessageSize) - if err != nil { - bs.doDropRPC(out, p, fmt.Sprintf("unable to fragment RPC: %s", err)) - return - } - + // Potentially split the RPC into multiple RPCs that are below the max message size + outRPCs := appendOrMergeRPC(nil, bs.p.maxMessageSize, *out) for _, rpc := range outRPCs { + if rpc.Size() > bs.p.maxMessageSize { + // This should only happen if a single message/control is above the maxMessageSize. + bs.doDropRPC(out, p, fmt.Sprintf("Dropping oversized RPC. Size: %d, limit: %d. (Over by %d bytes)", rpc.Size(), bs.p.maxMessageSize, rpc.Size()-bs.p.maxMessageSize)) + continue + } bs.doSendRPC(rpc, p, mch) } } func (bs *BlossomSubRouter) doDropRPC(rpc *RPC, p peer.ID, reason string) { - log.Debugf("dropping message to peer %s: %s", p.Pretty(), reason) + log.Debugf("dropping message to peer %s: %s", p, reason) bs.tracer.DropRPC(rpc, p) // push control messages that need to be retried ctl := rpc.GetControl() @@ -1219,119 +1268,134 @@ func (bs *BlossomSubRouter) doSendRPC(rpc *RPC, p peer.ID, mch chan *RPC) { } } -func fragmentRPC(rpc *RPC, limit int) ([]*RPC, error) { - if rpc.Size() < limit { - return []*RPC{rpc}, nil +// appendOrMergeRPC appends the given RPCs to the slice, merging them if possible. +// If any elem is too large to fit in a single RPC, it will be split into multiple RPCs. +// If an RPC is too large and can't be split further (e.g. Message data is +// bigger than the RPC limit), then it will be returned as an oversized RPC. +// The caller should filter out oversized RPCs. +func appendOrMergeRPC(slice []*RPC, limit int, elems ...RPC) []*RPC { + if len(elems) == 0 { + return slice } - c := (rpc.Size() / limit) + 1 - rpcs := make([]*RPC, 1, c) - rpcs[0] = &RPC{RPC: pb.RPC{}, from: rpc.from} + if len(slice) == 0 && len(elems) == 1 && elems[0].Size() < limit { + // Fast path: no merging needed and only one element + return append(slice, &elems[0]) + } - // outRPC returns the current RPC message if it will fit sizeToAdd more bytes - // otherwise, it will create a new RPC message and add it to the list. - // if withCtl is true, the returned message will have a non-nil empty Control message. - outRPC := func(sizeToAdd int, withCtl bool) *RPC { - current := rpcs[len(rpcs)-1] - // check if we can fit the new data, plus an extra byte for the protobuf field tag - if current.Size()+sizeToAdd+1 < limit { - if withCtl && current.Control == nil { - current.Control = &pb.ControlMessage{} + out := slice + if len(out) == 0 { + out = append(out, &RPC{RPC: pb.RPC{}}) + out[0].from = elems[0].from + } + + for _, elem := range elems { + lastRPC := out[len(out)-1] + + // Merge/Append publish messages + // TODO: Never merge messages. The current behavior is the same as the + // old behavior. In the future let's not merge messages. Since, + // it may increase message latency. + for _, msg := range elem.GetPublish() { + if lastRPC.Publish = append(lastRPC.Publish, msg); lastRPC.Size() > limit { + lastRPC.Publish = lastRPC.Publish[:len(lastRPC.Publish)-1] + lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from} + lastRPC.Publish = append(lastRPC.Publish, msg) + out = append(out, lastRPC) } - return current } - var ctl *pb.ControlMessage - if withCtl { - ctl = &pb.ControlMessage{} + + // Merge/Append Subscriptions + for _, sub := range elem.GetSubscriptions() { + if lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub); lastRPC.Size() > limit { + lastRPC.Subscriptions = lastRPC.Subscriptions[:len(lastRPC.Subscriptions)-1] + lastRPC = &RPC{RPC: pb.RPC{}, from: elem.from} + lastRPC.Subscriptions = append(lastRPC.Subscriptions, sub) + out = append(out, lastRPC) + } } - next := &RPC{RPC: pb.RPC{Control: ctl}, from: rpc.from} - rpcs = append(rpcs, next) - return next - } - for _, msg := range rpc.GetPublish() { - s := msg.Size() - // if an individual message is too large, we can't fragment it and have to fail entirely - if s > limit { - return nil, fmt.Errorf("message with len=%d exceeds limit %d", s, limit) - } - out := outRPC(s, false) - out.Publish = append(out.Publish, msg) - } + // Merge/Append Control messages + if ctl := elem.GetControl(); ctl != nil { + if lastRPC.Control == nil { + lastRPC.Control = &pb.ControlMessage{} + if lastRPC.Size() > limit { + lastRPC.Control = nil + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from} + out = append(out, lastRPC) + } + } - for _, sub := range rpc.GetSubscriptions() { - out := outRPC(sub.Size(), false) - out.Subscriptions = append(out.Subscriptions, sub) - } + for _, graft := range ctl.GetGraft() { + if lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft); lastRPC.Size() > limit { + lastRPC.Control.Graft = lastRPC.Control.Graft[:len(lastRPC.Control.Graft)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from} + lastRPC.Control.Graft = append(lastRPC.Control.Graft, graft) + out = append(out, lastRPC) + } + } - ctl := rpc.GetControl() - if ctl == nil { - // if there were no control messages, we're done - return rpcs, nil - } - // if all the control messages fit into one RPC, we just add it to the end and return - ctlOut := &RPC{RPC: pb.RPC{Control: ctl}, from: rpc.from} - if ctlOut.Size() < limit { - rpcs = append(rpcs, ctlOut) - return rpcs, nil - } + for _, prune := range ctl.GetPrune() { + if lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune); lastRPC.Size() > limit { + lastRPC.Control.Prune = lastRPC.Control.Prune[:len(lastRPC.Control.Prune)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{}}, from: elem.from} + lastRPC.Control.Prune = append(lastRPC.Control.Prune, prune) + out = append(out, lastRPC) + } + } - // we need to split up the control messages into multiple RPCs - for _, graft := range ctl.Graft { - out := outRPC(graft.Size(), true) - out.Control.Graft = append(out.Control.Graft, graft) - } - for _, prune := range ctl.Prune { - out := outRPC(prune.Size(), true) - out.Control.Prune = append(out.Control.Prune, prune) - } + for _, iwant := range ctl.GetIwant() { + if len(lastRPC.Control.Iwant) == 0 { + // Initialize with a single IWANT. + // For IWANTs we don't need more than a single one, + // since there are no bitmask IDs here. + newIWant := &pb.ControlIWant{} + if lastRPC.Control.Iwant = append(lastRPC.Control.Iwant, newIWant); lastRPC.Size() > limit { + lastRPC.Control.Iwant = lastRPC.Control.Iwant[:len(lastRPC.Control.Iwant)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{ + Iwant: []*pb.ControlIWant{newIWant}, + }}, from: elem.from} + out = append(out, lastRPC) + } + } + for _, msgID := range iwant.GetMessageIDs() { + if lastRPC.Control.Iwant[0].MessageIDs = append(lastRPC.Control.Iwant[0].MessageIDs, msgID); lastRPC.Size() > limit { + lastRPC.Control.Iwant[0].MessageIDs = lastRPC.Control.Iwant[0].MessageIDs[:len(lastRPC.Control.Iwant[0].MessageIDs)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{ + Iwant: []*pb.ControlIWant{{MessageIDs: []string{msgID}}}, + }}, from: elem.from} + out = append(out, lastRPC) + } + } + } - // An individual IWANT or IHAVE message could be larger than the limit if we have - // a lot of message IDs. fragmentMessageIds will split them into buckets that - // fit within the limit, with some overhead for the control messages themselves - for _, iwant := range ctl.Iwant { - const protobufOverhead = 6 - idBuckets := fragmentMessageIds(iwant.MessageIDs, limit-protobufOverhead) - for _, ids := range idBuckets { - iwant := &pb.ControlIWant{MessageIDs: ids} - out := outRPC(iwant.Size(), true) - out.Control.Iwant = append(out.Control.Iwant, iwant) + for _, ihave := range ctl.GetIhave() { + if len(lastRPC.Control.Ihave) == 0 || + !bytes.Equal(lastRPC.Control.Ihave[len(lastRPC.Control.Ihave)-1].Bitmask, ihave.Bitmask) { + // Start a new IHAVE if we are referencing a new bitmask ID + newIhave := &pb.ControlIHave{Bitmask: ihave.Bitmask} + if lastRPC.Control.Ihave = append(lastRPC.Control.Ihave, newIhave); lastRPC.Size() > limit { + lastRPC.Control.Ihave = lastRPC.Control.Ihave[:len(lastRPC.Control.Ihave)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{ + Ihave: []*pb.ControlIHave{newIhave}, + }}, from: elem.from} + out = append(out, lastRPC) + } + } + for _, msgID := range ihave.GetMessageIDs() { + lastIHave := lastRPC.Control.Ihave[len(lastRPC.Control.Ihave)-1] + if lastIHave.MessageIDs = append(lastIHave.MessageIDs, msgID); lastRPC.Size() > limit { + lastIHave.MessageIDs = lastIHave.MessageIDs[:len(lastIHave.MessageIDs)-1] + lastRPC = &RPC{RPC: pb.RPC{Control: &pb.ControlMessage{ + Ihave: []*pb.ControlIHave{{Bitmask: ihave.Bitmask, MessageIDs: []string{msgID}}}, + }}, from: elem.from} + out = append(out, lastRPC) + } + } + } } } - for _, ihave := range ctl.Ihave { - const protobufOverhead = 6 - idBuckets := fragmentMessageIds(ihave.MessageIDs, limit-protobufOverhead) - for _, ids := range idBuckets { - ihave := &pb.ControlIHave{MessageIDs: ids} - out := outRPC(ihave.Size(), true) - out.Control.Ihave = append(out.Control.Ihave, ihave) - } - } - return rpcs, nil -} -func fragmentMessageIds(msgIds []string, limit int) [][]string { - // account for two bytes of protobuf overhead per array element - const protobufOverhead = 2 - - out := [][]string{{}} - var currentBucket int - var bucketLen int - for i := 0; i < len(msgIds); i++ { - size := len(msgIds[i]) + protobufOverhead - if size > limit { - // pathological case where a single message ID exceeds the limit. - log.Warnf("message ID length %d exceeds limit %d, removing from outgoing gossip", size, limit) - continue - } - bucketLen += size - if bucketLen > limit { - out = append(out, []string{}) - currentBucket++ - bucketLen = size - } - out[currentBucket] = append(out[currentBucket], msgIds[i]) - } return out } diff --git a/go-libp2p-blossomsub/comm.go b/go-libp2p-blossomsub/comm.go index fa24ebd..2c36c07 100644 --- a/go-libp2p-blossomsub/comm.go +++ b/go-libp2p-blossomsub/comm.go @@ -76,6 +76,9 @@ func (p *PubSub) handleNewStream(s network.Stream) { return } + if len(msgbytes) == 0 { + continue + } rpc := new(RPC) err = rpc.Unmarshal(msgbytes) diff --git a/go-libp2p-blossomsub/go.mod b/go-libp2p-blossomsub/go.mod index aec4283..45db1c2 100644 --- a/go-libp2p-blossomsub/go.mod +++ b/go-libp2p-blossomsub/go.mod @@ -66,10 +66,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect - github.com/quic-go/qtls-go1-18 v0.2.0 // indirect - github.com/quic-go/qtls-go1-19 v0.2.0 // indirect - github.com/quic-go/qtls-go1-20 v0.1.0 // indirect - github.com/quic-go/quic-go v0.32.0 // indirect + github.com/quic-go/quic-go v0.37.5 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/stretchr/testify v1.8.1 // indirect diff --git a/go-libp2p-blossomsub/notify.go b/go-libp2p-blossomsub/notify.go index 4d9ef0f..770a54c 100644 --- a/go-libp2p-blossomsub/notify.go +++ b/go-libp2p-blossomsub/notify.go @@ -18,7 +18,7 @@ func (p *PubSubNotif) ClosedStream(n network.Network, s network.Stream) { func (p *PubSubNotif) Connected(n network.Network, c network.Conn) { // ignore transient connections - if c.Stat().Transient { + if c.Stat().Limited { return } @@ -48,7 +48,7 @@ func (p *PubSubNotif) ListenClose(n network.Network, _ ma.Multiaddr) { func (p *PubSubNotif) Initialize() { isTransient := func(pid peer.ID) bool { for _, c := range p.host.Network().ConnsToPeer(pid) { - if !c.Stat().Transient { + if !c.Stat().Limited { return false } } diff --git a/go-libp2p-blossomsub/peer_gater.go b/go-libp2p-blossomsub/peer_gater.go index c4610ad..1922000 100644 --- a/go-libp2p-blossomsub/peer_gater.go +++ b/go-libp2p-blossomsub/peer_gater.go @@ -303,7 +303,7 @@ func (pg *peerGater) getPeerIP(p peer.ID) string { // most streams; it's a nightmare to track multiple IPs per peer, so pick the best one. streams := make(map[string]int) for _, c := range conns { - if c.Stat().Transient { + if c.Stat().Limited { // ignore transient continue } diff --git a/go-libp2p-blossomsub/score.go b/go-libp2p-blossomsub/score.go index 32a66d8..8816bc5 100644 --- a/go-libp2p-blossomsub/score.go +++ b/go-libp2p-blossomsub/score.go @@ -990,7 +990,7 @@ func (ps *peerScore) getIPs(p peer.ID) []string { conns := ps.host.Network().ConnsToPeer(p) res := make([]string, 0, 1) for _, c := range conns { - if c.Stat().Transient { + if c.Stat().Limited { // ignore transient continue } diff --git a/go-libp2p-gostream/go.mod b/go-libp2p-gostream/go.mod index 1961155..b7c96bb 100644 --- a/go-libp2p-gostream/go.mod +++ b/go-libp2p-gostream/go.mod @@ -72,8 +72,7 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.2.3 // indirect - github.com/quic-go/quic-go v0.36.3 // indirect + github.com/quic-go/quic-go v0.37.5 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect diff --git a/go-libp2p/.github/ISSUE_TEMPLATE/config.yml b/go-libp2p/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..1ba3fd8 --- /dev/null +++ b/go-libp2p/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Technical Questions + url: https://github.com/libp2p/go-libp2p/discussions/new?category=q-a + about: Please ask technical questions in the go-libp2p Github Discusions forum. + - name: Community-wide libp2p Discussion + url: https://discuss.libp2p.io + about: Discussions and questions about the libp2p community. diff --git a/go-libp2p/.github/workflows/automerge.yml b/go-libp2p/.github/workflows/automerge.yml deleted file mode 100644 index 3833fc2..0000000 --- a/go-libp2p/.github/workflows/automerge.yml +++ /dev/null @@ -1,11 +0,0 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - -name: Automerge -on: [ pull_request ] - -jobs: - automerge: - uses: protocol/.github/.github/workflows/automerge.yml@master - with: - job: 'automerge' diff --git a/go-libp2p/.github/workflows/go-check.yml b/go-libp2p/.github/workflows/go-check.yml index cc65ce6..a1cc205 100644 --- a/go-libp2p/.github/workflows/go-check.yml +++ b/go-libp2p/.github/workflows/go-check.yml @@ -1,67 +1,20 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - -on: [push, pull_request] name: Go Checks +on: + pull_request: + push: + branches: ["master","release-v0[0-9][0-9]"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + jobs: - unit: - runs-on: ubuntu-latest - name: All - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - id: config - uses: protocol/.github/.github/actions/read-config@master - - uses: actions/setup-go@v3 - with: - go-version: 1.20.x - - name: Run repo-specific setup - uses: ./.github/actions/go-check-setup - if: hashFiles('./.github/actions/go-check-setup') != '' - - name: Install staticcheck - run: go install honnef.co/go/tools/cmd/staticcheck@4970552d932f48b71485287748246cf3237cebdf # 2023.1 (v0.4.0) - - name: Check that go.mod is tidy - uses: protocol/multiple-go-modules@v1.2 - with: - run: | - go mod tidy - if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then - echo "go.sum was added by go mod tidy" - exit 1 - fi - git diff --exit-code -- go.sum go.mod - - name: gofmt - if: success() || failure() # run this step even if the previous one failed - run: | - out=$(gofmt -s -l .) - if [[ -n "$out" ]]; then - echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}' - exit 1 - fi - - name: go vet - if: success() || failure() # run this step even if the previous one failed - uses: protocol/multiple-go-modules@v1.2 - with: - run: go vet ./... - - name: staticcheck - if: success() || failure() # run this step even if the previous one failed - uses: protocol/multiple-go-modules@v1.2 - with: - run: | - set -o pipefail - staticcheck ./... | sed -e 's@\(.*\)\.go@./\1.go@g' - - name: go generate - uses: protocol/multiple-go-modules@v1.2 - if: (success() || failure()) && fromJSON(steps.config.outputs.json).gogenerate == true - with: - run: | - git clean -fd # make sure there aren't untracked files / directories - go generate -x ./... - # check if go generate modified or added any files - if ! $(git add . && git diff-index HEAD --exit-code --quiet); then - echo "go generated caused changes to the repository:" - git status --short - exit 1 - fi + go-check: + uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 + with: + go-generate-ignore-protoc-version-comments: true diff --git a/go-libp2p/.github/workflows/go-test.yml b/go-libp2p/.github/workflows/go-test.yml index c5cb3ef..e33480c 100644 --- a/go-libp2p/.github/workflows/go-test.yml +++ b/go-libp2p/.github/workflows/go-test.yml @@ -1,76 +1,22 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - -on: [push, pull_request] name: Go Test +on: + pull_request: + push: + branches: ["master","release-v0[0-9][0-9]"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + jobs: - unit: - strategy: - fail-fast: false - matrix: - os: [ "ubuntu", "windows", "macos" ] - go: ["1.19.x","1.20.x"] - env: - COVERAGES: "" - runs-on: ${{ fromJSON(vars[format('UCI_GO_TEST_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }} - name: ${{ matrix.os }} (go ${{ matrix.go }}) - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - id: config - uses: protocol/.github/.github/actions/read-config@master - - uses: actions/setup-go@v3 - with: - go-version: ${{ matrix.go }} - - name: Go information - run: | - go version - go env - - name: Use msys2 on windows - if: matrix.os == 'windows' - shell: bash - # The executable for msys2 is also called bash.cmd - # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#shells - # If we prepend its location to the PATH - # subsequent 'shell: bash' steps will use msys2 instead of gitbash - run: echo "C:/msys64/usr/bin" >> $GITHUB_PATH - - name: Run repo-specific setup - uses: ./.github/actions/go-test-setup - if: hashFiles('./.github/actions/go-test-setup') != '' - - name: Run tests - if: contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false - uses: protocol/multiple-go-modules@v1.2 - with: - # Use -coverpkg=./..., so that we include cross-package coverage. - # If package ./A imports ./B, and ./A's tests also cover ./B, - # this means ./B's coverage will be significantly higher than 0%. - run: go test -v -shuffle=on -coverprofile=module-coverage.txt -coverpkg=./... ./... - - name: Run tests (32 bit) - # can't run 32 bit tests on OSX. - if: matrix.os != 'macos' && - fromJSON(steps.config.outputs.json).skip32bit != true && - contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false - uses: protocol/multiple-go-modules@v1.2 - env: - GOARCH: 386 - with: - run: | - export "PATH=$PATH_386:$PATH" - go test -v -shuffle=on ./... - - name: Run tests with race detector - # speed things up. Windows and OSX VMs are slow - if: matrix.os == 'ubuntu' && - contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false - uses: protocol/multiple-go-modules@v1.2 - with: - run: go test -v -race ./... - - name: Collect coverage files - shell: bash - run: echo "COVERAGES=$(find . -type f -name 'module-coverage.txt' | tr -s '\n' ',' | sed 's/,$//')" >> $GITHUB_ENV - - name: Upload coverage to Codecov - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 - with: - files: '${{ env.COVERAGES }}' - env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }} + go-test: + uses: libp2p/uci/.github/workflows/go-test.yml@v1.0 + with: + go-versions: '["1.21.x", "1.22.x"]' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/go-libp2p/.github/workflows/interop-test.yml b/go-libp2p/.github/workflows/interop-test.yml index c5f2a5e..f320553 100644 --- a/go-libp2p/.github/workflows/interop-test.yml +++ b/go-libp2p/.github/workflows/interop-test.yml @@ -1,19 +1,32 @@ name: Interoperability Testing on: + workflow_dispatch: pull_request: + paths: + - 'config/**' + - 'core/**' + - 'internal/**' + - 'p2p/**' + - 'test-plans/**' push: branches: - "master" + paths: + - 'config/**' + - 'core/**' + - 'internal/**' + - 'p2p/**' + - 'test-plans/**' jobs: - run-multidim-interop: - name: Run multidimensional interoperability tests + run-transport-interop: + name: Run transport interoperability tests runs-on: ${{ fromJSON(vars['INTEROP_TEST_RUNNER_UBUNTU'] || '"ubuntu-22.04"') }} steps: - uses: actions/checkout@v3 - name: Build image run: docker build -t go-libp2p-head -f test-plans/PingDockerfile . - - uses: libp2p/test-plans/.github/actions/run-interop-ping-test@master + - uses: libp2p/test-plans/.github/actions/run-transport-interop-test@master with: test-filter: go-libp2p-head extra-versions: ${{ github.workspace }}/test-plans/ping-version.json diff --git a/go-libp2p/.github/workflows/release-check.yml b/go-libp2p/.github/workflows/release-check.yml index e2408e3..0b5ff60 100644 --- a/go-libp2p/.github/workflows/release-check.yml +++ b/go-libp2p/.github/workflows/release-check.yml @@ -1,13 +1,19 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - name: Release Checker + on: pull_request_target: paths: [ 'version.json' ] + types: [ opened, synchronize, reopened, labeled, unlabeled ] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: release-check: - uses: protocol/.github/.github/workflows/release-check.yml@master - with: - go-version: 1.20.x + uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 diff --git a/go-libp2p/.github/workflows/releaser.yml b/go-libp2p/.github/workflows/releaser.yml index cdccbf8..2ebdbed 100644 --- a/go-libp2p/.github/workflows/releaser.yml +++ b/go-libp2p/.github/workflows/releaser.yml @@ -1,11 +1,17 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - name: Releaser + on: push: paths: [ 'version.json' ] + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: true jobs: releaser: - uses: protocol/.github/.github/workflows/releaser.yml@master + uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 diff --git a/go-libp2p/.github/workflows/tagpush.yml b/go-libp2p/.github/workflows/tagpush.yml index d849961..5ef3fb9 100644 --- a/go-libp2p/.github/workflows/tagpush.yml +++ b/go-libp2p/.github/workflows/tagpush.yml @@ -1,12 +1,18 @@ -# File managed by web3-bot. DO NOT EDIT. -# See https://github.com/protocol/.github/ for details. - name: Tag Push Checker + on: push: tags: - v* +permissions: + contents: read + issues: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: releaser: - uses: protocol/.github/.github/workflows/tagpush.yml@master + uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 diff --git a/go-libp2p/README.md b/go-libp2p/README.md index 155f466..960d89e 100644 --- a/go-libp2p/README.md +++ b/go-libp2p/README.md @@ -1,6 +1,6 @@

- libp2p hex logo + libp2p hex logo

The Go implementation of the libp2p Networking Stack.

@@ -18,6 +18,7 @@ - [Roadmap](#roadmap) - [Usage](#usage) - [Examples](#examples) + - [Dashboards](#dashboards) - [Contribute](#contribute) - [Supported Go Versions](#supported-go-versions) - [Notable Users](#notable-users) @@ -54,6 +55,13 @@ import "github.com/libp2p/go-libp2p" Examples can be found in the [examples folder](examples). +## Dashboards + +We provide prebuilt Grafana dashboards so that applications can better monitor libp2p in production. +You can find the [dashboard JSON files here](https://github.com/libp2p/go-libp2p/tree/master/dashboards). + +We also have live [Public Dashboards](https://github.com/libp2p/go-libp2p/tree/master/dashboards/README.md#public-dashboards) that you can check out to see real time monitoring in action. + # Contribute @@ -75,7 +83,7 @@ There's a few things you can do right now to help out: ## Supported Go Versions We test against and support the two most recent major releases of Go. This is -informed by Go's own [security policy](https://go.dev/security). +informed by Go's own [security policy](https://go.dev/doc/security/policy). # Notable Users Some notable users of go-libp2p are: diff --git a/go-libp2p/config/config.go b/go-libp2p/config/config.go index cea8ef1..cc689ba 100644 --- a/go-libp2p/config/config.go +++ b/go-libp2p/config/config.go @@ -1,6 +1,7 @@ package config import ( + "context" "crypto/rand" "errors" "fmt" @@ -23,7 +24,6 @@ import ( "github.com/libp2p/go-libp2p/p2p/host/autonat" "github.com/libp2p/go-libp2p/p2p/host/autorelay" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" - blankhost "github.com/libp2p/go-libp2p/p2p/host/blank" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" @@ -38,6 +38,7 @@ import ( ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" + "github.com/quic-go/quic-go" "go.uber.org/fx" "go.uber.org/fx/fxevent" ) @@ -128,6 +129,8 @@ type Config struct { DialRanker network.DialRanker SwarmOpts []swarm.Option + + DisableIdentifyAddressDiscovery bool } func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) { @@ -190,20 +193,11 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa return swarm.NewSwarm(pid, cfg.Peerstore, eventBus, opts...) } -func (cfg *Config) addTransports(h host.Host) error { - swrm, ok := h.Network().(transport.TransportNetwork) - if !ok { - // Should probably skip this if no transports. - return fmt.Errorf("swarm does not support transports") - } - +func (cfg *Config) addTransports() ([]fx.Option, error) { fxopts := []fx.Option{ fx.WithLogger(func() fxevent.Logger { return getFXLogger() }), fx.Provide(fx.Annotate(tptu.New, fx.ParamTags(`name:"security"`))), fx.Supply(cfg.Muxers), - fx.Supply(h.ID()), - fx.Provide(func() host.Host { return h }), - fx.Provide(func() crypto.PrivKey { return h.Peerstore().PrivKey(h.ID()) }), fx.Provide(func() connmgr.ConnectionGater { return cfg.ConnectionGater }), fx.Provide(func() pnet.PSK { return cfg.PSK }), fx.Provide(func() network.ResourceManager { return cfg.ResourceManager }), @@ -261,15 +255,25 @@ func (cfg *Config) addTransports(h host.Host) error { } fxopts = append(fxopts, fx.Provide(PrivKeyToStatelessResetKey)) + fxopts = append(fxopts, fx.Provide(PrivKeyToTokenGeneratorKey)) if cfg.QUICReuse != nil { fxopts = append(fxopts, cfg.QUICReuse...) } else { - fxopts = append(fxopts, fx.Provide(quicreuse.NewConnManager)) // TODO: close the ConnManager when shutting down the node + fxopts = append(fxopts, + fx.Provide(func(key quic.StatelessResetKey, tokenGenerator quic.TokenGeneratorKey, _ *swarm.Swarm, lifecycle fx.Lifecycle) (*quicreuse.ConnManager, error) { + cm, err := quicreuse.NewConnManager(key, tokenGenerator) + if err != nil { + return nil, err + } + lifecycle.Append(fx.StopHook(cm.Close)) + return cm, nil + }), + ) } fxopts = append(fxopts, fx.Invoke( fx.Annotate( - func(tpts []transport.Transport) error { + func(swrm *swarm.Swarm, tpts []transport.Transport) error { for _, t := range tpts { if err := swrm.AddTransport(t); err != nil { return err @@ -277,54 +281,35 @@ func (cfg *Config) addTransports(h host.Host) error { } return nil }, - fx.ParamTags(`group:"transport"`), + fx.ParamTags("", `group:"transport"`), )), ) if cfg.Relay { fxopts = append(fxopts, fx.Invoke(circuitv2.AddTransport)) } - app := fx.New(fxopts...) - if err := app.Err(); err != nil { - h.Close() - return err - } - return nil + return fxopts, nil } -// NewNode constructs a new libp2p Host from the Config. -// -// This function consumes the config. Do not reuse it (really!). -func (cfg *Config) NewNode() (host.Host, error) { - eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer)))) - swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics) - if err != nil { - return nil, err - } - - if !cfg.DisableMetrics { - rcmgr.MustRegisterWith(cfg.PrometheusRegisterer) - } - +func (cfg *Config) newBasicHost(swrm *swarm.Swarm, eventBus event.Bus) (*bhost.BasicHost, error) { h, err := bhost.NewHost(swrm, &bhost.HostOpts{ - EventBus: eventBus, - ConnManager: cfg.ConnManager, - AddrsFactory: cfg.AddrsFactory, - NATManager: cfg.NATManager, - EnablePing: !cfg.DisablePing, - UserAgent: cfg.UserAgent, - ProtocolVersion: cfg.ProtocolVersion, - EnableHolePunching: cfg.EnableHolePunching, - HolePunchingOptions: cfg.HolePunchingOptions, - EnableRelayService: cfg.EnableRelayService, - RelayServiceOpts: cfg.RelayServiceOpts, - EnableMetrics: !cfg.DisableMetrics, - PrometheusRegisterer: cfg.PrometheusRegisterer, + EventBus: eventBus, + ConnManager: cfg.ConnManager, + AddrsFactory: cfg.AddrsFactory, + NATManager: cfg.NATManager, + EnablePing: !cfg.DisablePing, + UserAgent: cfg.UserAgent, + ProtocolVersion: cfg.ProtocolVersion, + EnableHolePunching: cfg.EnableHolePunching, + HolePunchingOptions: cfg.HolePunchingOptions, + EnableRelayService: cfg.EnableRelayService, + RelayServiceOpts: cfg.RelayServiceOpts, + EnableMetrics: !cfg.DisableMetrics, + PrometheusRegisterer: cfg.PrometheusRegisterer, + DisableIdentifyAddressDiscovery: cfg.DisableIdentifyAddressDiscovery, }) if err != nil { - swrm.Close() return nil, err } - if cfg.Relay { // If we've enabled the relay, we should filter out relay // addresses by default. @@ -335,60 +320,144 @@ func (cfg *Config) NewNode() (host.Host, error) { return oldFactory(autorelay.Filter(addrs)) } } + return h, nil +} - if err := cfg.addTransports(h); err != nil { - h.Close() - return nil, err +// NewNode constructs a new libp2p Host from the Config. +// +// This function consumes the config. Do not reuse it (really!). +func (cfg *Config) NewNode() (host.Host, error) { + if cfg.EnableAutoRelay && !cfg.Relay { + return nil, fmt.Errorf("cannot enable autorelay; relay is not enabled") + } + // If possible check that the resource manager conn limit is higher than the + // limit set in the conn manager. + if l, ok := cfg.ResourceManager.(connmgr.GetConnLimiter); ok { + err := cfg.ConnManager.CheckLimit(l) + if err != nil { + log.Warn(fmt.Sprintf("rcmgr limit conflicts with connmgr limit: %v", err)) + } } - // TODO: This method succeeds if listening on one address succeeds. We - // should probably fail if listening on *any* addr fails. - if err := h.Network().Listen(cfg.ListenAddrs...); err != nil { - h.Close() + if !cfg.DisableMetrics { + rcmgr.MustRegisterWith(cfg.PrometheusRegisterer) + } + + fxopts := []fx.Option{ + fx.Provide(func() event.Bus { + return eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer)))) + }), + fx.Provide(func(eventBus event.Bus, lifecycle fx.Lifecycle) (*swarm.Swarm, error) { + sw, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics) + if err != nil { + return nil, err + } + lifecycle.Append(fx.StopHook(sw.Close)) + return sw, nil + }), + // Make sure the swarm constructor depends on the quicreuse.ConnManager. + // That way, the ConnManager will be started before the swarm, and more importantly, + // the swarm will be stopped before the ConnManager. + fx.Decorate(func(sw *swarm.Swarm, _ *quicreuse.ConnManager, lifecycle fx.Lifecycle) *swarm.Swarm { + lifecycle.Append(fx.Hook{ + OnStart: func(context.Context) error { + // TODO: This method succeeds if listening on one address succeeds. We + // should probably fail if listening on *any* addr fails. + return sw.Listen(cfg.ListenAddrs...) + }, + OnStop: func(context.Context) error { + return sw.Close() + }, + }) + return sw + }), + fx.Provide(cfg.newBasicHost), + fx.Provide(func(bh *bhost.BasicHost) host.Host { + return bh + }), + fx.Provide(func(h *swarm.Swarm) peer.ID { return h.LocalPeer() }), + fx.Provide(func(h *swarm.Swarm) crypto.PrivKey { return h.Peerstore().PrivKey(h.LocalPeer()) }), + } + transportOpts, err := cfg.addTransports() + if err != nil { return nil, err } + fxopts = append(fxopts, transportOpts...) // Configure routing and autorelay - var router routing.PeerRouting if cfg.Routing != nil { - router, err = cfg.Routing(h) - if err != nil { - h.Close() - return nil, err - } + fxopts = append(fxopts, + fx.Provide(cfg.Routing), + fx.Provide(func(h host.Host, router routing.PeerRouting) *routed.RoutedHost { + return routed.Wrap(h, router) + }), + ) } // Note: h.AddrsFactory may be changed by relayFinder, but non-relay version is // used by AutoNAT below. - var ar *autorelay.AutoRelay - addrF := h.AddrsFactory if cfg.EnableAutoRelay { - if !cfg.Relay { - h.Close() - return nil, fmt.Errorf("cannot enable autorelay; relay is not enabled") - } if !cfg.DisableMetrics { mt := autorelay.WithMetricsTracer( autorelay.NewMetricsTracer(autorelay.WithRegisterer(cfg.PrometheusRegisterer))) mtOpts := []autorelay.Option{mt} cfg.AutoRelayOpts = append(mtOpts, cfg.AutoRelayOpts...) } - - ar, err = autorelay.NewAutoRelay(h, cfg.AutoRelayOpts...) - if err != nil { - return nil, err - } + fxopts = append(fxopts, + fx.Invoke(func(h *bhost.BasicHost, lifecycle fx.Lifecycle) (*autorelay.AutoRelay, error) { + ar, err := autorelay.NewAutoRelay(h, cfg.AutoRelayOpts...) + if err != nil { + return nil, err + } + lifecycle.Append(fx.StartStopHook(ar.Start, ar.Close)) + return ar, nil + }), + ) } + var bh *bhost.BasicHost + fxopts = append(fxopts, fx.Invoke(func(bho *bhost.BasicHost) { bh = bho })) + fxopts = append(fxopts, fx.Invoke(func(h *bhost.BasicHost, lifecycle fx.Lifecycle) { + lifecycle.Append(fx.StartHook(h.Start)) + })) + + var rh *routed.RoutedHost + if cfg.Routing != nil { + fxopts = append(fxopts, fx.Invoke(func(bho *routed.RoutedHost) { rh = bho })) + } + + app := fx.New(fxopts...) + if err := app.Start(context.Background()); err != nil { + return nil, err + } + + if err := cfg.addAutoNAT(bh); err != nil { + app.Stop(context.Background()) + if cfg.Routing != nil { + rh.Close() + } else { + bh.Close() + } + return nil, err + } + + if cfg.Routing != nil { + return &closableRoutedHost{App: app, RoutedHost: rh}, nil + } + return &closableBasicHost{App: app, BasicHost: bh}, nil +} + +func (cfg *Config) addAutoNAT(h *bhost.BasicHost) error { + addrF := h.AddrsFactory autonatOpts := []autonat.Option{ autonat.UsingAddresses(func() []ma.Multiaddr { return addrF(h.AllAddrs()) }), } if !cfg.DisableMetrics { - autonatOpts = append(autonatOpts, - autonat.WithMetricsTracer( - autonat.NewMetricsTracer(autonat.WithRegisterer(cfg.PrometheusRegisterer)))) + autonatOpts = append(autonatOpts, autonat.WithMetricsTracer( + autonat.NewMetricsTracer(autonat.WithRegisterer(cfg.PrometheusRegisterer)), + )) } if cfg.AutoNATConfig.ThrottleInterval != 0 { autonatOpts = append(autonatOpts, @@ -398,16 +467,15 @@ func (cfg *Config) NewNode() (host.Host, error) { if cfg.AutoNATConfig.EnableService { autonatPrivKey, _, err := crypto.GenerateEd25519Key(rand.Reader) if err != nil { - return nil, err + return err } ps, err := pstoremem.NewPeerstore() if err != nil { - return nil, err + return err } // Pull out the pieces of the config that we _actually_ care about. - // Specifically, don't set up things like autorelay, listeners, - // identify, etc. + // Specifically, don't set up things like listeners, identify, etc. autoNatCfg := Config{ Transports: cfg.Transports, Muxers: cfg.Muxers, @@ -419,23 +487,47 @@ func (cfg *Config) NewNode() (host.Host, error) { PeerKey: autonatPrivKey, Peerstore: ps, DialRanker: swarm.NoDelayDialRanker, + SwarmOpts: []swarm.Option{ + // It is better to disable black hole detection and just attempt a dial for autonat + swarm.WithUDPBlackHoleConfig(false, 0, 0), + swarm.WithIPv6BlackHoleConfig(false, 0, 0), + }, } - dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false) + fxopts, err := autoNatCfg.addTransports() if err != nil { - h.Close() - return nil, err + return err } - dialerHost := blankhost.NewBlankHost(dialer) - if err := autoNatCfg.addTransports(dialerHost); err != nil { - dialerHost.Close() - h.Close() - return nil, err + var dialer *swarm.Swarm + + fxopts = append(fxopts, + fx.Provide(eventbus.NewBus), + fx.Provide(func(lifecycle fx.Lifecycle, b event.Bus) (*swarm.Swarm, error) { + lifecycle.Append(fx.Hook{ + OnStop: func(context.Context) error { + return ps.Close() + }}) + var err error + dialer, err = autoNatCfg.makeSwarm(b, false) + return dialer, err + + }), + fx.Provide(func(s *swarm.Swarm) peer.ID { return s.LocalPeer() }), + fx.Provide(func() crypto.PrivKey { return autonatPrivKey }), + ) + app := fx.New(fxopts...) + if err := app.Err(); err != nil { + return err } - // NOTE: We're dropping the blank host here but that's fine. It - // doesn't really _do_ anything and doesn't even need to be - // closed (as long as we close the underlying network). - autonatOpts = append(autonatOpts, autonat.EnableService(dialerHost.Network())) + err = app.Start(context.Background()) + if err != nil { + return err + } + go func() { + <-dialer.Done() // The swarm used for autonat has closed, we can cleanup now + app.Stop(context.Background()) + }() + autonatOpts = append(autonatOpts, autonat.EnableService(dialer)) } if cfg.AutoNATConfig.ForceReachability != nil { autonatOpts = append(autonatOpts, autonat.WithReachability(*cfg.AutoNATConfig.ForceReachability)) @@ -443,25 +535,10 @@ func (cfg *Config) NewNode() (host.Host, error) { autonat, err := autonat.New(h, autonatOpts...) if err != nil { - h.Close() - return nil, fmt.Errorf("cannot enable autorelay; autonat failed to start: %v", err) + return fmt.Errorf("cannot enable autorelay; autonat failed to start: %v", err) } h.SetAutoNat(autonat) - - // start the host background tasks - h.Start() - - var ho host.Host - ho = h - if router != nil { - ho = routed.Wrap(h, router) - } - if ar != nil { - arh := autorelay.NewAutoRelayHost(ho, ar) - arh.Start() - ho = arh - } - return ho, nil + return nil } // Option is a libp2p config option that can be given to the libp2p constructor diff --git a/go-libp2p/config/host.go b/go-libp2p/config/host.go new file mode 100644 index 0000000..ac61df2 --- /dev/null +++ b/go-libp2p/config/host.go @@ -0,0 +1,30 @@ +package config + +import ( + "context" + + basichost "github.com/libp2p/go-libp2p/p2p/host/basic" + routed "github.com/libp2p/go-libp2p/p2p/host/routed" + + "go.uber.org/fx" +) + +type closableBasicHost struct { + *fx.App + *basichost.BasicHost +} + +func (h *closableBasicHost) Close() error { + _ = h.App.Stop(context.Background()) + return h.BasicHost.Close() +} + +type closableRoutedHost struct { + *fx.App + *routed.RoutedHost +} + +func (h *closableRoutedHost) Close() error { + _ = h.App.Stop(context.Background()) + return h.RoutedHost.Close() +} diff --git a/go-libp2p/config/quic_stateless_reset.go b/go-libp2p/config/quic.go similarity index 53% rename from go-libp2p/config/quic_stateless_reset.go rename to go-libp2p/config/quic.go index a12be56..66c40da 100644 --- a/go-libp2p/config/quic_stateless_reset.go +++ b/go-libp2p/config/quic.go @@ -11,7 +11,10 @@ import ( "github.com/quic-go/quic-go" ) -const statelessResetKeyInfo = "libp2p quic stateless reset key" +const ( + statelessResetKeyInfo = "libp2p quic stateless reset key" + tokenGeneratorKeyInfo = "libp2p quic token generator key" +) func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, error) { var statelessResetKey quic.StatelessResetKey @@ -25,3 +28,16 @@ func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, err } return statelessResetKey, nil } + +func PrivKeyToTokenGeneratorKey(key crypto.PrivKey) (quic.TokenGeneratorKey, error) { + var tokenKey quic.TokenGeneratorKey + keyBytes, err := key.Raw() + if err != nil { + return tokenKey, err + } + keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(tokenGeneratorKeyInfo)) + if _, err := io.ReadFull(keyReader, tokenKey[:]); err != nil { + return tokenKey, err + } + return tokenKey, nil +} diff --git a/go-libp2p/core/connmgr/manager.go b/go-libp2p/core/connmgr/manager.go index e0d6c52..d756e43 100644 --- a/go-libp2p/core/connmgr/manager.go +++ b/go-libp2p/core/connmgr/manager.go @@ -74,6 +74,10 @@ type ConnManager interface { // then it will return true if the peer is protected for any tag IsProtected(id peer.ID, tag string) (protected bool) + // CheckLimit will return an error if the connection manager's internal + // connection limit exceeds the provided system limit. + CheckLimit(l GetConnLimiter) error + // Close closes the connection manager and stops background processes. Close() error } @@ -89,3 +93,9 @@ type TagInfo struct { // Conns maps connection ids (such as remote multiaddr) to their creation time. Conns map[string]time.Time } + +// GetConnLimiter provides access to a component's total connection limit. +type GetConnLimiter interface { + // GetConnLimit returns the total connection limit of the implementing component. + GetConnLimit() int +} diff --git a/go-libp2p/core/connmgr/null.go b/go-libp2p/core/connmgr/null.go index 25743f4..7354117 100644 --- a/go-libp2p/core/connmgr/null.go +++ b/go-libp2p/core/connmgr/null.go @@ -21,4 +21,5 @@ func (NullConnMgr) Notifee() network.Notifiee { return network.Gl func (NullConnMgr) Protect(peer.ID, string) {} func (NullConnMgr) Unprotect(peer.ID, string) bool { return false } func (NullConnMgr) IsProtected(peer.ID, string) bool { return false } +func (NullConnMgr) CheckLimit(l GetConnLimiter) error { return nil } func (NullConnMgr) Close() error { return nil } diff --git a/go-libp2p/core/crypto/ecdsa.go b/go-libp2p/core/crypto/ecdsa.go index c936d50..c890afe 100644 --- a/go-libp2p/core/crypto/ecdsa.go +++ b/go-libp2p/core/crypto/ecdsa.go @@ -4,6 +4,7 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" + "crypto/sha256" "crypto/x509" "encoding/asn1" "errors" @@ -12,8 +13,6 @@ import ( pb "github.com/libp2p/go-libp2p/core/crypto/pb" "github.com/libp2p/go-libp2p/core/internal/catch" - - "github.com/minio/sha256-simd" ) // ECDSAPrivateKey is an implementation of an ECDSA private key diff --git a/go-libp2p/core/crypto/ecdsa_test.go b/go-libp2p/core/crypto/ecdsa_test.go index cc75d57..6e4720d 100644 --- a/go-libp2p/core/crypto/ecdsa_test.go +++ b/go-libp2p/core/crypto/ecdsa_test.go @@ -25,7 +25,7 @@ func TestECDSABasicSignAndVerify(t *testing.T) { } if !ok { - t.Fatal("signature didnt match") + t.Fatal("signature didn't match") } // change data diff --git a/go-libp2p/core/crypto/key.go b/go-libp2p/core/crypto/key.go index 2c25be2..036c1e7 100644 --- a/go-libp2p/core/crypto/key.go +++ b/go-libp2p/core/crypto/key.go @@ -4,12 +4,10 @@ package crypto import ( - "crypto/elliptic" "crypto/rand" "crypto/subtle" "encoding/base64" "errors" - "fmt" "io" "github.com/libp2p/go-libp2p/core/crypto/pb" @@ -129,51 +127,6 @@ func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, e } } -// GenerateEKeyPair returns an ephemeral public key and returns a function that will compute -// the shared secret key. Used in the identify module. -// -// Focuses only on ECDH now, but can be made more general in the future. -func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) { - var curve elliptic.Curve - - switch curveName { - case "P-256": - curve = elliptic.P256() - case "P-384": - curve = elliptic.P384() - case "P-521": - curve = elliptic.P521() - default: - return nil, nil, fmt.Errorf("unknown curve name") - } - - priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) - if err != nil { - return nil, nil, err - } - - pubKey := elliptic.Marshal(curve, x, y) - - done := func(theirPub []byte) ([]byte, error) { - // Verify and unpack node's public key. - x, y := elliptic.Unmarshal(curve, theirPub) - if x == nil { - return nil, fmt.Errorf("malformed public key: %d %v", len(theirPub), theirPub) - } - - if !curve.IsOnCurve(x, y) { - return nil, errors.New("invalid public key") - } - - // Generate shared secret. - secret, _ := curve.ScalarMult(x, y, priv) - - return secret.Bytes(), nil - } - - return pubKey, done, nil -} - // UnmarshalPublicKey converts a protobuf serialized public key into its // representative object func UnmarshalPublicKey(data []byte) (PubKey, error) { diff --git a/go-libp2p/core/crypto/key_test.go b/go-libp2p/core/crypto/key_test.go index 2db4453..e9a3b0a 100644 --- a/go-libp2p/core/crypto/key_test.go +++ b/go-libp2p/core/crypto/key_test.go @@ -8,19 +8,19 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + "crypto/sha256" "crypto/x509" "fmt" "reflect" "testing" - "github.com/cloudflare/circl/sign/ed448" . "github.com/libp2p/go-libp2p/core/crypto" pb "github.com/libp2p/go-libp2p/core/crypto/pb" "github.com/libp2p/go-libp2p/core/test" + "github.com/cloudflare/circl/sign/ed448" "github.com/decred/dcrd/dcrec/secp256k1/v4" secp256k1ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" - "github.com/minio/sha256-simd" ) func TestKeys(t *testing.T) { @@ -307,15 +307,3 @@ func testKeyEquals(t *testing.T, k Key) { t.Fatal("Keys should not equal.") } } - -func TestUnknownCurveErrors(t *testing.T) { - _, _, err := GenerateEKeyPair("P-256") - if err != nil { - t.Fatal(err) - } - - _, _, err = GenerateEKeyPair("error-please") - if err == nil { - t.Fatal("expected invalid key type to error") - } -} diff --git a/go-libp2p/core/crypto/key_to_stdlib.go b/go-libp2p/core/crypto/key_to_stdlib.go index 8d5d8c0..219cb55 100644 --- a/go-libp2p/core/crypto/key_to_stdlib.go +++ b/go-libp2p/core/crypto/key_to_stdlib.go @@ -28,16 +28,16 @@ func KeyPairFromStdKey(priv crypto.PrivateKey) (PrivKey, PubKey, error) { pub, _ := pubIfc.(ed25519.PublicKey) return &Ed25519PrivateKey{*p}, &Ed25519PublicKey{pub}, nil - case *secp256k1.PrivateKey: - sPriv := Secp256k1PrivateKey(*p) - sPub := Secp256k1PublicKey(*p.PubKey()) - return &sPriv, &sPub, nil - case *ed448.PrivateKey: pubIfc := p.Public() pub, _ := pubIfc.(ed448.PublicKey) return &Ed448PrivateKey{*p}, &Ed448PublicKey{pub}, nil + case *secp256k1.PrivateKey: + sPriv := Secp256k1PrivateKey(*p) + sPub := Secp256k1PublicKey(*p.PubKey()) + return &sPriv, &sPub, nil + default: return nil, nil, ErrBadKeyType } @@ -56,10 +56,10 @@ func PrivKeyToStdKey(priv PrivKey) (crypto.PrivateKey, error) { return p.priv, nil case *Ed25519PrivateKey: return &p.k, nil - case *Secp256k1PrivateKey: - return p, nil case *Ed448PrivateKey: return &p.k, nil + case *Secp256k1PrivateKey: + return p, nil default: return nil, ErrBadKeyType } @@ -78,10 +78,10 @@ func PubKeyToStdKey(pub PubKey) (crypto.PublicKey, error) { return p.pub, nil case *Ed25519PublicKey: return p.k, nil - case *Secp256k1PublicKey: - return p, nil case *Ed448PublicKey: return p.k, nil + case *Secp256k1PublicKey: + return p, nil default: return nil, ErrBadKeyType } diff --git a/go-libp2p/core/crypto/pb/crypto.pb.go b/go-libp2p/core/crypto/pb/crypto.pb.go index eb88361..903daf4 100644 --- a/go-libp2p/core/crypto/pb/crypto.pb.go +++ b/go-libp2p/core/crypto/pb/crypto.pb.go @@ -37,7 +37,6 @@ var ( 1: "Ed25519", 2: "Secp256k1", 3: "ECDSA", - 4: "Ed448", } KeyType_value = map[string]int32{ "RSA": 0, diff --git a/go-libp2p/core/crypto/rsa_go.go b/go-libp2p/core/crypto/rsa_go.go index 8981ba6..845dae9 100644 --- a/go-libp2p/core/crypto/rsa_go.go +++ b/go-libp2p/core/crypto/rsa_go.go @@ -4,14 +4,13 @@ import ( "crypto" "crypto/rand" "crypto/rsa" + "crypto/sha256" "crypto/x509" "errors" "io" pb "github.com/libp2p/go-libp2p/core/crypto/pb" "github.com/libp2p/go-libp2p/core/internal/catch" - - "github.com/minio/sha256-simd" ) // RsaPrivateKey is a rsa private key diff --git a/go-libp2p/core/crypto/rsa_test.go b/go-libp2p/core/crypto/rsa_test.go index f4a7971..dbc88dd 100644 --- a/go-libp2p/core/crypto/rsa_test.go +++ b/go-libp2p/core/crypto/rsa_test.go @@ -24,7 +24,7 @@ func TestRSABasicSignAndVerify(t *testing.T) { } if !ok { - t.Fatal("signature didnt match") + t.Fatal("signature didn't match") } // change data diff --git a/go-libp2p/core/crypto/secp256k1.go b/go-libp2p/core/crypto/secp256k1.go index 27544a5..99e7464 100644 --- a/go-libp2p/core/crypto/secp256k1.go +++ b/go-libp2p/core/crypto/secp256k1.go @@ -1,6 +1,7 @@ package crypto import ( + "crypto/sha256" "fmt" "io" @@ -9,7 +10,6 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" - "github.com/minio/sha256-simd" ) // Secp256k1PrivateKey is a Secp256k1 private key diff --git a/go-libp2p/core/crypto/secp256k1_test.go b/go-libp2p/core/crypto/secp256k1_test.go index 81f2f57..67bbe47 100644 --- a/go-libp2p/core/crypto/secp256k1_test.go +++ b/go-libp2p/core/crypto/secp256k1_test.go @@ -24,7 +24,7 @@ func TestSecp256k1BasicSignAndVerify(t *testing.T) { } if !ok { - t.Fatal("signature didnt match") + t.Fatal("signature didn't match") } // change data diff --git a/go-libp2p/core/event/identify.go b/go-libp2p/core/event/identify.go index ff14995..888572a 100644 --- a/go-libp2p/core/event/identify.go +++ b/go-libp2p/core/event/identify.go @@ -1,11 +1,40 @@ package event -import "github.com/libp2p/go-libp2p/core/peer" +import ( + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/protocol" + "github.com/libp2p/go-libp2p/core/record" + "github.com/multiformats/go-multiaddr" +) // EvtPeerIdentificationCompleted is emitted when the initial identification round for a peer is completed. type EvtPeerIdentificationCompleted struct { // Peer is the ID of the peer whose identification succeeded. Peer peer.ID + + // Conn is the connection we identified. + Conn network.Conn + + // ListenAddrs is the list of addresses the peer is listening on. + ListenAddrs []multiaddr.Multiaddr + + // Protocols is the list of protocols the peer advertised on this connection. + Protocols []protocol.ID + + // SignedPeerRecord is the provided signed peer record of the peer. May be nil. + SignedPeerRecord *record.Envelope + + // AgentVersion is like a UserAgent string in browsers, or client version in + // bittorrent includes the client name and client. + AgentVersion string + + // ProtocolVersion is the protocolVersion field in the identify message + ProtocolVersion string + + // ObservedAddr is the our side's connection address as observed by the + // peer. This is not verified, the peer could return anything here. + ObservedAddr multiaddr.Multiaddr } // EvtPeerIdentificationFailed is emitted when the initial identification round for a peer failed. diff --git a/go-libp2p/core/network/context.go b/go-libp2p/core/network/context.go index 7fabfb5..75db775 100644 --- a/go-libp2p/core/network/context.go +++ b/go-libp2p/core/network/context.go @@ -13,12 +13,12 @@ var DialPeerTimeout = 60 * time.Second type noDialCtxKey struct{} type dialPeerTimeoutCtxKey struct{} type forceDirectDialCtxKey struct{} -type useTransientCtxKey struct{} +type allowLimitedConnCtxKey struct{} type simConnectCtxKey struct{ isClient bool } var noDial = noDialCtxKey{} var forceDirectDial = forceDirectDialCtxKey{} -var useTransient = useTransientCtxKey{} +var allowLimitedConn = allowLimitedConnCtxKey{} var simConnectIsServer = simConnectCtxKey{} var simConnectIsClient = simConnectCtxKey{isClient: true} @@ -94,15 +94,35 @@ func WithDialPeerTimeout(ctx context.Context, timeout time.Duration) context.Con return context.WithValue(ctx, dialPeerTimeoutCtxKey{}, timeout) } -// WithUseTransient constructs a new context with an option that instructs the network -// that it is acceptable to use a transient connection when opening a new stream. -func WithUseTransient(ctx context.Context, reason string) context.Context { - return context.WithValue(ctx, useTransient, reason) +// WithAllowLimitedConn constructs a new context with an option that instructs +// the network that it is acceptable to use a limited connection when opening a +// new stream. +func WithAllowLimitedConn(ctx context.Context, reason string) context.Context { + return context.WithValue(ctx, allowLimitedConn, reason) } -// GetUseTransient returns true if the use transient option is set in the context. -func GetUseTransient(ctx context.Context) (usetransient bool, reason string) { - v := ctx.Value(useTransient) +// WithUseTransient constructs a new context with an option that instructs the network +// that it is acceptable to use a transient connection when opening a new stream. +// +// Deprecated: Use WithAllowLimitedConn instead. +func WithUseTransient(ctx context.Context, reason string) context.Context { + return context.WithValue(ctx, allowLimitedConn, reason) +} + +// GetAllowLimitedConn returns true if the allow limited conn option is set in the context. +func GetAllowLimitedConn(ctx context.Context) (usetransient bool, reason string) { + v := ctx.Value(allowLimitedConn) + if v != nil { + return true, v.(string) + } + return false, "" +} + +// GetUseTransient returns true if the use transient option is set in the context. +// +// Deprecated: Use GetAllowLimitedConn instead. +func GetUseTransient(ctx context.Context) (usetransient bool, reason string) { + v := ctx.Value(allowLimitedConn) if v != nil { return true, v.(string) } diff --git a/go-libp2p/core/network/context_test.go b/go-libp2p/core/network/context_test.go index b12def5..65a8654 100644 --- a/go-libp2p/core/network/context_test.go +++ b/go-libp2p/core/network/context_test.go @@ -47,13 +47,13 @@ func TestSimultaneousConnect(t *testing.T) { ok, isClient, reason := GetSimultaneousConnect(serverCtx) require.True(t, ok) require.False(t, isClient) - require.Equal(t, reason, "foobar") + require.Equal(t, "foobar", reason) }) t.Run("for the client", func(t *testing.T) { serverCtx := WithSimultaneousConnect(context.Background(), true, "foo") ok, isClient, reason := GetSimultaneousConnect(serverCtx) require.True(t, ok) require.True(t, isClient) - require.Equal(t, reason, "foo") + require.Equal(t, "foo", reason) }) } diff --git a/go-libp2p/core/network/errors.go b/go-libp2p/core/network/errors.go index 03bb90c..0f98cd5 100644 --- a/go-libp2p/core/network/errors.go +++ b/go-libp2p/core/network/errors.go @@ -22,7 +22,13 @@ var ErrNoConn = errors.New("no usable connection to peer") // ErrTransientConn is returned when attempting to open a stream to a peer with only a transient // connection, without specifying the UseTransient option. -var ErrTransientConn = errors.New("transient connection to peer") +// +// Deprecated: Use ErrLimitedConn instead. +var ErrTransientConn = ErrLimitedConn + +// ErrLimitedConn is returned when attempting to open a stream to a peer with only a conn +// connection, without specifying the AllowLimitedConn option. +var ErrLimitedConn = errors.New("limited connection to peer") // ErrResourceLimitExceeded is returned when attempting to perform an operation that would // exceed system resource limits. diff --git a/go-libp2p/core/network/mocks/mock_conn_management_scope.go b/go-libp2p/core/network/mocks/mock_conn_management_scope.go index 5d847f9..d6538e1 100644 --- a/go-libp2p/core/network/mocks/mock_conn_management_scope.go +++ b/go-libp2p/core/network/mocks/mock_conn_management_scope.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ConnManagementScope) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_conn_management_scope.go github.com/libp2p/go-libp2p/core/network ConnManagementScope +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,9 +12,9 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" + gomock "go.uber.org/mock/gomock" ) // MockConnManagementScope is a mock of ConnManagementScope interface. @@ -83,7 +88,7 @@ func (m *MockConnManagementScope) ReleaseMemory(arg0 int) { } // ReleaseMemory indicates an expected call of ReleaseMemory. -func (mr *MockConnManagementScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { +func (mr *MockConnManagementScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockConnManagementScope)(nil).ReleaseMemory), arg0) } @@ -97,7 +102,7 @@ func (m *MockConnManagementScope) ReserveMemory(arg0 int, arg1 byte) error { } // ReserveMemory indicates an expected call of ReserveMemory. -func (mr *MockConnManagementScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockConnManagementScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockConnManagementScope)(nil).ReserveMemory), arg0, arg1) } @@ -111,7 +116,7 @@ func (m *MockConnManagementScope) SetPeer(arg0 peer.ID) error { } // SetPeer indicates an expected call of SetPeer. -func (mr *MockConnManagementScopeMockRecorder) SetPeer(arg0 interface{}) *gomock.Call { +func (mr *MockConnManagementScopeMockRecorder) SetPeer(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPeer", reflect.TypeOf((*MockConnManagementScope)(nil).SetPeer), arg0) } diff --git a/go-libp2p/core/network/mocks/mock_peer_scope.go b/go-libp2p/core/network/mocks/mock_peer_scope.go index 1633839..325a894 100644 --- a/go-libp2p/core/network/mocks/mock_peer_scope.go +++ b/go-libp2p/core/network/mocks/mock_peer_scope.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: PeerScope) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_peer_scope.go github.com/libp2p/go-libp2p/core/network PeerScope +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,9 +12,9 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" + gomock "go.uber.org/mock/gomock" ) // MockPeerScope is a mock of PeerScope interface. @@ -71,7 +76,7 @@ func (m *MockPeerScope) ReleaseMemory(arg0 int) { } // ReleaseMemory indicates an expected call of ReleaseMemory. -func (mr *MockPeerScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { +func (mr *MockPeerScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockPeerScope)(nil).ReleaseMemory), arg0) } @@ -85,7 +90,7 @@ func (m *MockPeerScope) ReserveMemory(arg0 int, arg1 byte) error { } // ReserveMemory indicates an expected call of ReserveMemory. -func (mr *MockPeerScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockPeerScope)(nil).ReserveMemory), arg0, arg1) } diff --git a/go-libp2p/core/network/mocks/mock_protocol_scope.go b/go-libp2p/core/network/mocks/mock_protocol_scope.go index 646eede..80d2967 100644 --- a/go-libp2p/core/network/mocks/mock_protocol_scope.go +++ b/go-libp2p/core/network/mocks/mock_protocol_scope.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ProtocolScope) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_protocol_scope.go github.com/libp2p/go-libp2p/core/network ProtocolScope +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,9 +12,9 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" protocol "github.com/libp2p/go-libp2p/core/protocol" + gomock "go.uber.org/mock/gomock" ) // MockProtocolScope is a mock of ProtocolScope interface. @@ -71,7 +76,7 @@ func (m *MockProtocolScope) ReleaseMemory(arg0 int) { } // ReleaseMemory indicates an expected call of ReleaseMemory. -func (mr *MockProtocolScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { +func (mr *MockProtocolScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockProtocolScope)(nil).ReleaseMemory), arg0) } @@ -85,7 +90,7 @@ func (m *MockProtocolScope) ReserveMemory(arg0 int, arg1 byte) error { } // ReserveMemory indicates an expected call of ReserveMemory. -func (mr *MockProtocolScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockProtocolScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockProtocolScope)(nil).ReserveMemory), arg0, arg1) } diff --git a/go-libp2p/core/network/mocks/mock_resource_manager.go b/go-libp2p/core/network/mocks/mock_resource_manager.go index dbf6219..98e186e 100644 --- a/go-libp2p/core/network/mocks/mock_resource_manager.go +++ b/go-libp2p/core/network/mocks/mock_resource_manager.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ResourceManager) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_resource_manager.go github.com/libp2p/go-libp2p/core/network ResourceManager +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,11 +12,11 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" protocol "github.com/libp2p/go-libp2p/core/protocol" multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" ) // MockResourceManager is a mock of ResourceManager interface. @@ -61,7 +66,7 @@ func (m *MockResourceManager) OpenConnection(arg0 network.Direction, arg1 bool, } // OpenConnection indicates an expected call of OpenConnection. -func (mr *MockResourceManagerMockRecorder) OpenConnection(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) OpenConnection(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenConnection", reflect.TypeOf((*MockResourceManager)(nil).OpenConnection), arg0, arg1, arg2) } @@ -76,7 +81,7 @@ func (m *MockResourceManager) OpenStream(arg0 peer.ID, arg1 network.Direction) ( } // OpenStream indicates an expected call of OpenStream. -func (mr *MockResourceManagerMockRecorder) OpenStream(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) OpenStream(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStream", reflect.TypeOf((*MockResourceManager)(nil).OpenStream), arg0, arg1) } @@ -90,7 +95,7 @@ func (m *MockResourceManager) ViewPeer(arg0 peer.ID, arg1 func(network.PeerScope } // ViewPeer indicates an expected call of ViewPeer. -func (mr *MockResourceManagerMockRecorder) ViewPeer(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) ViewPeer(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewPeer", reflect.TypeOf((*MockResourceManager)(nil).ViewPeer), arg0, arg1) } @@ -104,7 +109,7 @@ func (m *MockResourceManager) ViewProtocol(arg0 protocol.ID, arg1 func(network.P } // ViewProtocol indicates an expected call of ViewProtocol. -func (mr *MockResourceManagerMockRecorder) ViewProtocol(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) ViewProtocol(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewProtocol", reflect.TypeOf((*MockResourceManager)(nil).ViewProtocol), arg0, arg1) } @@ -118,7 +123,7 @@ func (m *MockResourceManager) ViewService(arg0 string, arg1 func(network.Service } // ViewService indicates an expected call of ViewService. -func (mr *MockResourceManagerMockRecorder) ViewService(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) ViewService(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewService", reflect.TypeOf((*MockResourceManager)(nil).ViewService), arg0, arg1) } @@ -132,7 +137,7 @@ func (m *MockResourceManager) ViewSystem(arg0 func(network.ResourceScope) error) } // ViewSystem indicates an expected call of ViewSystem. -func (mr *MockResourceManagerMockRecorder) ViewSystem(arg0 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) ViewSystem(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewSystem", reflect.TypeOf((*MockResourceManager)(nil).ViewSystem), arg0) } @@ -146,7 +151,7 @@ func (m *MockResourceManager) ViewTransient(arg0 func(network.ResourceScope) err } // ViewTransient indicates an expected call of ViewTransient. -func (mr *MockResourceManagerMockRecorder) ViewTransient(arg0 interface{}) *gomock.Call { +func (mr *MockResourceManagerMockRecorder) ViewTransient(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewTransient", reflect.TypeOf((*MockResourceManager)(nil).ViewTransient), arg0) } diff --git a/go-libp2p/core/network/mocks/mock_resource_scope_span.go b/go-libp2p/core/network/mocks/mock_resource_scope_span.go index ba9a424..5123ff8 100644 --- a/go-libp2p/core/network/mocks/mock_resource_scope_span.go +++ b/go-libp2p/core/network/mocks/mock_resource_scope_span.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ResourceScopeSpan) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_resource_scope_span.go github.com/libp2p/go-libp2p/core/network ResourceScopeSpan +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,8 +12,8 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" + gomock "go.uber.org/mock/gomock" ) // MockResourceScopeSpan is a mock of ResourceScopeSpan interface. @@ -68,7 +73,7 @@ func (m *MockResourceScopeSpan) ReleaseMemory(arg0 int) { } // ReleaseMemory indicates an expected call of ReleaseMemory. -func (mr *MockResourceScopeSpanMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { +func (mr *MockResourceScopeSpanMockRecorder) ReleaseMemory(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReleaseMemory), arg0) } @@ -82,7 +87,7 @@ func (m *MockResourceScopeSpan) ReserveMemory(arg0 int, arg1 byte) error { } // ReserveMemory indicates an expected call of ReserveMemory. -func (mr *MockResourceScopeSpanMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockResourceScopeSpanMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReserveMemory), arg0, arg1) } diff --git a/go-libp2p/core/network/mocks/mock_stream_management_scope.go b/go-libp2p/core/network/mocks/mock_stream_management_scope.go index 7dace90..472eb7a 100644 --- a/go-libp2p/core/network/mocks/mock_stream_management_scope.go +++ b/go-libp2p/core/network/mocks/mock_stream_management_scope.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/network (interfaces: StreamManagementScope) +// +// Generated by this command: +// +// mockgen -package mocknetwork -destination mock_stream_management_scope.go github.com/libp2p/go-libp2p/core/network StreamManagementScope +// // Package mocknetwork is a generated GoMock package. package mocknetwork @@ -7,9 +12,9 @@ package mocknetwork import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" network "github.com/libp2p/go-libp2p/core/network" protocol "github.com/libp2p/go-libp2p/core/protocol" + gomock "go.uber.org/mock/gomock" ) // MockStreamManagementScope is a mock of StreamManagementScope interface. @@ -97,7 +102,7 @@ func (m *MockStreamManagementScope) ReleaseMemory(arg0 int) { } // ReleaseMemory indicates an expected call of ReleaseMemory. -func (mr *MockStreamManagementScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call { +func (mr *MockStreamManagementScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockStreamManagementScope)(nil).ReleaseMemory), arg0) } @@ -111,7 +116,7 @@ func (m *MockStreamManagementScope) ReserveMemory(arg0 int, arg1 byte) error { } // ReserveMemory indicates an expected call of ReserveMemory. -func (mr *MockStreamManagementScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockStreamManagementScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockStreamManagementScope)(nil).ReserveMemory), arg0, arg1) } @@ -139,7 +144,7 @@ func (m *MockStreamManagementScope) SetProtocol(arg0 protocol.ID) error { } // SetProtocol indicates an expected call of SetProtocol. -func (mr *MockStreamManagementScopeMockRecorder) SetProtocol(arg0 interface{}) *gomock.Call { +func (mr *MockStreamManagementScopeMockRecorder) SetProtocol(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProtocol", reflect.TypeOf((*MockStreamManagementScope)(nil).SetProtocol), arg0) } @@ -153,7 +158,7 @@ func (m *MockStreamManagementScope) SetService(arg0 string) error { } // SetService indicates an expected call of SetService. -func (mr *MockStreamManagementScopeMockRecorder) SetService(arg0 interface{}) *gomock.Call { +func (mr *MockStreamManagementScopeMockRecorder) SetService(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetService", reflect.TypeOf((*MockStreamManagementScope)(nil).SetService), arg0) } diff --git a/go-libp2p/core/network/mocks/network.go b/go-libp2p/core/network/mocks/network.go index 6fe8e91..73025bd 100644 --- a/go-libp2p/core/network/mocks/network.go +++ b/go-libp2p/core/network/mocks/network.go @@ -1,8 +1,8 @@ package mocknetwork -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_resource_manager.go github.com/libp2p/go-libp2p/core/network ResourceManager" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_conn_management_scope.go github.com/libp2p/go-libp2p/core/network ConnManagementScope" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_stream_management_scope.go github.com/libp2p/go-libp2p/core/network StreamManagementScope" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_peer_scope.go github.com/libp2p/go-libp2p/core/network PeerScope" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_protocol_scope.go github.com/libp2p/go-libp2p/core/network ProtocolScope" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocknetwork -destination mock_resource_scope_span.go github.com/libp2p/go-libp2p/core/network ResourceScopeSpan" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_resource_manager.go github.com/libp2p/go-libp2p/core/network ResourceManager" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_conn_management_scope.go github.com/libp2p/go-libp2p/core/network ConnManagementScope" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_stream_management_scope.go github.com/libp2p/go-libp2p/core/network StreamManagementScope" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_peer_scope.go github.com/libp2p/go-libp2p/core/network PeerScope" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_protocol_scope.go github.com/libp2p/go-libp2p/core/network ProtocolScope" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocknetwork -destination mock_resource_scope_span.go github.com/libp2p/go-libp2p/core/network ResourceScopeSpan" diff --git a/go-libp2p/core/network/network.go b/go-libp2p/core/network/network.go index 66b0a1c..22efbf2 100644 --- a/go-libp2p/core/network/network.go +++ b/go-libp2p/core/network/network.go @@ -55,16 +55,23 @@ const ( // Connected means has an open, live connection to peer Connected + // Deprecated: CanConnect is deprecated and will be removed in a future release. + // // CanConnect means recently connected to peer, terminated gracefully CanConnect + // Deprecated: CannotConnect is deprecated and will be removed in a future release. + // // CannotConnect means recently attempted connecting but failed to connect. // (should signal "made effort, failed") CannotConnect + + // Limited means we have a transient connection to the peer, but aren't fully connected. + Limited ) func (c Connectedness) String() string { - str := [...]string{"NotConnected", "Connected", "CanConnect", "CannotConnect"} + str := [...]string{"NotConnected", "Connected", "CanConnect", "CannotConnect", "Limited"} if c < 0 || int(c) >= len(str) { return unrecognized } @@ -111,8 +118,10 @@ type Stats struct { Direction Direction // Opened is the timestamp when this connection was opened. Opened time.Time - // Transient indicates that this connection is transient and may be closed soon. - Transient bool + // Limited indicates that this connection is Limited. It maybe limited by + // bytes or time. In practice, this is a connection formed over a circuit v2 + // relay. + Limited bool // Extra stores additional metadata about this connection. Extra map[interface{}]interface{} } diff --git a/go-libp2p/core/peer/addrinfo.go b/go-libp2p/core/peer/addrinfo.go index fba4cfd..de7dd4d 100644 --- a/go-libp2p/core/peer/addrinfo.go +++ b/go-libp2p/core/peer/addrinfo.go @@ -86,7 +86,7 @@ func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) { // AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs. func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { - p2ppart, err := ma.NewComponent("p2p", Encode(pi.ID)) + p2ppart, err := ma.NewComponent("p2p", pi.ID.String()) if err != nil { return nil, err } @@ -102,7 +102,7 @@ func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { func (pi *AddrInfo) Loggable() map[string]interface{} { return map[string]interface{}{ - "peerID": pi.ID.Pretty(), + "peerID": pi.ID.String(), "addrs": pi.Addrs, } } diff --git a/go-libp2p/core/peer/addrinfo_test.go b/go-libp2p/core/peer/addrinfo_test.go index 9f18a8b..3fd1556 100644 --- a/go-libp2p/core/peer/addrinfo_test.go +++ b/go-libp2p/core/peer/addrinfo_test.go @@ -3,9 +3,9 @@ package peer_test import ( "testing" - ma "github.com/multiformats/go-multiaddr" - . "github.com/libp2p/go-libp2p/core/peer" + + ma "github.com/multiformats/go-multiaddr" ) var ( @@ -19,7 +19,7 @@ func init() { if err != nil { panic(err) } - maddrPeer = ma.StringCast("/p2p/" + Encode(testID)) + maddrPeer = ma.StringCast("/p2p/" + testID.String()) maddrTpt = ma.StringCast("/ip4/127.0.0.1/tcp/1234") maddrFull = maddrTpt.Encapsulate(maddrPeer) } @@ -115,7 +115,7 @@ func TestAddrInfosFromP2pAddrs(t *testing.T) { t.Fatal(err) } for _, info := range infos { - exaddrs, ok := expected[info.ID.Pretty()] + exaddrs, ok := expected[info.ID.String()] if !ok { t.Fatalf("didn't expect peer %s", info.ID) } @@ -129,7 +129,7 @@ func TestAddrInfosFromP2pAddrs(t *testing.T) { t.Fatalf("expected %s, got %s", exaddrs[i], addr) } } - delete(expected, info.ID.Pretty()) + delete(expected, info.ID.String()) } } @@ -144,7 +144,7 @@ func TestAddrInfoJSON(t *testing.T) { t.Fatal(err) } if addrInfo.ID != testID { - t.Fatalf("expected ID to equal %s, got %s", testID.Pretty(), addrInfo.ID.Pretty()) + t.Fatalf("expected ID to equal %s, got %s", testID, addrInfo.ID) } if len(addrInfo.Addrs) != 1 || !addrInfo.Addrs[0].Equal(maddrFull) { t.Fatalf("expected addrs to match %v, got %v", maddrFull, addrInfo.Addrs) diff --git a/go-libp2p/core/peer/peer.go b/go-libp2p/core/peer/peer.go index f7f649f..b77fb68 100644 --- a/go-libp2p/core/peer/peer.go +++ b/go-libp2p/core/peer/peer.go @@ -41,12 +41,6 @@ const maxInlineKeyLength = 42 // hash output as a multihash. See IDFromPublicKey for details. type ID string -// Pretty returns a base58-encoded string representation of the ID. -// Deprecated: use String() instead. -func (id ID) Pretty() string { - return id.String() -} - // Loggable returns a pretty peer ID string in loggable JSON format. func (id ID) Loggable() map[string]interface{} { return map[string]interface{}{ @@ -145,16 +139,6 @@ func Decode(s string) (ID, error) { return FromCid(c) } -// Encode encodes a peer ID as a string. -// -// At the moment, it base58 encodes the peer ID but, in the future, it will -// switch to encoding it as a CID by default. -// -// Deprecated: use id.String instead. -func Encode(id ID) string { - return id.String() -} - // FromCid converts a CID to a peer ID, if possible. func FromCid(c cid.Cid) (ID, error) { code := mc.Code(c.Type()) diff --git a/go-libp2p/core/peer/peer_serde.go b/go-libp2p/core/peer/peer_serde.go index 5fd1cd5..3e2f717 100644 --- a/go-libp2p/core/peer/peer_serde.go +++ b/go-libp2p/core/peer/peer_serde.go @@ -45,7 +45,7 @@ func (id ID) Size() int { } func (id ID) MarshalJSON() ([]byte, error) { - return json.Marshal(Encode(id)) + return json.Marshal(id.String()) } func (id *ID) UnmarshalJSON(data []byte) (err error) { @@ -59,7 +59,7 @@ func (id *ID) UnmarshalJSON(data []byte) (err error) { // MarshalText returns the text encoding of the ID. func (id ID) MarshalText() ([]byte, error) { - return []byte(Encode(id)), nil + return []byte(id.String()), nil } // UnmarshalText restores the ID from its text encoding. diff --git a/go-libp2p/core/peerstore/peerstore.go b/go-libp2p/core/peerstore/peerstore.go index 4c9227f..0ef09df 100644 --- a/go-libp2p/core/peerstore/peerstore.go +++ b/go-libp2p/core/peerstore/peerstore.go @@ -28,9 +28,10 @@ var ( // RecentlyConnectedAddrTTL is used when we recently connected to a peer. // It means that we are reasonably certain of the peer's address. - RecentlyConnectedAddrTTL = time.Minute * 30 + RecentlyConnectedAddrTTL = time.Minute * 15 // OwnObservedAddrTTL is used for our own external addresses observed by peers. + // Deprecated: observed addresses are maintained till we disconnect from the peer which provided it OwnObservedAddrTTL = time.Minute * 30 ) diff --git a/go-libp2p/core/routing/routing.go b/go-libp2p/core/routing/routing.go index e1d4745..b995b05 100644 --- a/go-libp2p/core/routing/routing.go +++ b/go-libp2p/core/routing/routing.go @@ -76,7 +76,7 @@ type Routing interface { ValueStore // Bootstrap allows callers to hint to the routing system to get into a - // Boostrapped state and remain there. It is not a synchronous call. + // Bootstrapped state and remain there. It is not a synchronous call. Bootstrap(context.Context) error // TODO expose io.Closer or plain-old Close error diff --git a/go-libp2p/core/sec/security.go b/go-libp2p/core/sec/security.go index 83059d9..d9e9183 100644 --- a/go-libp2p/core/sec/security.go +++ b/go-libp2p/core/sec/security.go @@ -3,6 +3,7 @@ package sec import ( "context" + "fmt" "net" "github.com/libp2p/go-libp2p/core/network" @@ -29,3 +30,14 @@ type SecureTransport interface { // ID is the protocol ID of the security protocol. ID() protocol.ID } + +type ErrPeerIDMismatch struct { + Expected peer.ID + Actual peer.ID +} + +func (e ErrPeerIDMismatch) Error() string { + return fmt.Sprintf("peer id mismatch: expected %s, but remote key matches %s", e.Expected, e.Actual) +} + +var _ error = (*ErrPeerIDMismatch)(nil) diff --git a/go-libp2p/core/transport/transport.go b/go-libp2p/core/transport/transport.go index 89a9608..d56a3cf 100644 --- a/go-libp2p/core/transport/transport.go +++ b/go-libp2p/core/transport/transport.go @@ -5,6 +5,7 @@ package transport import ( "context" "errors" + "fmt" "net" "github.com/libp2p/go-libp2p/core/network" @@ -124,3 +125,47 @@ type Upgrader interface { // Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection. Upgrade(ctx context.Context, t Transport, maconn manet.Conn, dir network.Direction, p peer.ID, scope network.ConnManagementScope) (CapableConn, error) } + +// DialUpdater provides updates on in progress dials. +type DialUpdater interface { + // DialWithUpdates dials a remote peer and provides updates on the passed channel. + DialWithUpdates(context.Context, ma.Multiaddr, peer.ID, chan<- DialUpdate) (CapableConn, error) +} + +// DialUpdateKind indicates the type of DialUpdate event. +type DialUpdateKind int + +const ( + // UpdateKindDialFailed indicates dial failed. + UpdateKindDialFailed DialUpdateKind = iota + // UpdateKindDialSuccessful indicates dial succeeded. + UpdateKindDialSuccessful + // UpdateKindHandshakeProgressed indicates successful completion of the TCP 3-way + // handshake + UpdateKindHandshakeProgressed +) + +func (k DialUpdateKind) String() string { + switch k { + case UpdateKindDialFailed: + return "DialFailed" + case UpdateKindDialSuccessful: + return "DialSuccessful" + case UpdateKindHandshakeProgressed: + return "UpdateKindHandshakeProgressed" + default: + return fmt.Sprintf("DialUpdateKind", k) + } +} + +// DialUpdate is used by DialUpdater to provide dial updates. +type DialUpdate struct { + // Kind is the kind of update event. + Kind DialUpdateKind + // Addr is the peer's address. + Addr ma.Multiaddr + // Conn is the resulting connection on success. + Conn CapableConn + // Err is the reason for dial failure. + Err error +} diff --git a/go-libp2p/dashboards/README.md b/go-libp2p/dashboards/README.md index 6080dc0..c371685 100644 --- a/go-libp2p/dashboards/README.md +++ b/go-libp2p/dashboards/README.md @@ -3,6 +3,20 @@ This directory contains prebuilt dashboards (provided as JSON files) for various components. For steps on how to import and use them [please read the official Grafana documentation.](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard) +## Public dashboards + +You can check the following prebuilt dashboards in action: + +1. [AutoNAT](https://protocollabs.grafana.net/public-dashboards/fce8fdeb629742c89bd70f0ce38dfd97) +2. [Auto Relay](https://protocollabs.grafana.net/public-dashboards/380d52aded12404e9cf6ceccb824b7f9) +3. [Eventbus](https://protocollabs.grafana.net/public-dashboards/048029ac2d7e4a71b281ffea3535026e) +4. [Identify](https://protocollabs.grafana.net/public-dashboards/96b70328253d47c0b352dfae06f12a1b) +5. [Relay Service](https://protocollabs.grafana.net/public-dashboards/4a8cb5d245294893874ed65279b049be) +6. [Swarm](https://protocollabs.grafana.net/public-dashboards/2bd3f1bee9964d40b6786fbe3eafd9fc) + +These metrics come from one of the public IPFS DHT [bootstrap nodes](https://docs.ipfs.tech/concepts/nodes/#bootstrap) run by Protocol Labs. +At the time of writing (2023-08), these nodes handle many connections across various libp2p implementations, versions, and configurations (they don't handle large file transfers). + ## Using locally For local development and debugging, it can be useful to spin up a local Prometheus and Grafana instance. diff --git a/go-libp2p/dashboards/autonat/autonat.json b/go-libp2p/dashboards/autonat/autonat.json index 4a14de8..fea5b7a 100644 --- a/go-libp2p/dashboards/autonat/autonat.json +++ b/go-libp2p/dashboards/autonat/autonat.json @@ -730,7 +730,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p autonat", + "title": "go-libp2p autonat", "uid": "YNWSyiJ4k", "version": 5, "weekStart": "" diff --git a/go-libp2p/dashboards/docker-compose.base.yml b/go-libp2p/dashboards/docker-compose.base.yml index 4c87d28..b46514a 100644 --- a/go-libp2p/dashboards/docker-compose.base.yml +++ b/go-libp2p/dashboards/docker-compose.base.yml @@ -26,3 +26,4 @@ services: - ./identify/identify.json:/var/lib/grafana/dashboards/identify.json - ./relaysvc/relaysvc.json:/var/lib/grafana/dashboards/relaysvc.json - ./swarm/swarm.json:/var/lib/grafana/dashboards/swarm.json + - ./resource-manager/resource-manager.json:/var/lib/grafana/dashboards/resource-manager.json diff --git a/go-libp2p/dashboards/eventbus/eventbus.json b/go-libp2p/dashboards/eventbus/eventbus.json index 24b7e22..f51549a 100644 --- a/go-libp2p/dashboards/eventbus/eventbus.json +++ b/go-libp2p/dashboards/eventbus/eventbus.json @@ -554,7 +554,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p EventBus", + "title": "go-libp2p EventBus", "uid": "ZFbI6NAVn", "version": 4, "weekStart": "" diff --git a/go-libp2p/dashboards/holepunch/holepunch.json b/go-libp2p/dashboards/holepunch/holepunch.json index ba20951..7d986f7 100644 --- a/go-libp2p/dashboards/holepunch/holepunch.json +++ b/go-libp2p/dashboards/holepunch/holepunch.json @@ -1129,7 +1129,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p Hole Punches", + "title": "go-libp2p Hole Punches", "uid": "Ao24vOBVk", "version": 6, "weekStart": "" diff --git a/go-libp2p/dashboards/identify/identify.json b/go-libp2p/dashboards/identify/identify.json index 41d7823..4f4631c 100644 --- a/go-libp2p/dashboards/identify/identify.json +++ b/go-libp2p/dashboards/identify/identify.json @@ -877,7 +877,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p Identify", + "title": "go-libp2p Identify", "uid": "0NDzQQ0Vz", "version": 2, "weekStart": "" diff --git a/go-libp2p/dashboards/relaysvc/relaysvc.json b/go-libp2p/dashboards/relaysvc/relaysvc.json index d70a824..c2a0e22 100644 --- a/go-libp2p/dashboards/relaysvc/relaysvc.json +++ b/go-libp2p/dashboards/relaysvc/relaysvc.json @@ -1229,7 +1229,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p Relay Service", + "title": "go-libp2p Relay Service", "uid": "C6RUfAx4z", "version": 5, "weekStart": "" diff --git a/go-libp2p/dashboards/resource-manager/resource-manager.json b/go-libp2p/dashboards/resource-manager/resource-manager.json index 8395b2a..9b4ff68 100644 --- a/go-libp2p/dashboards/resource-manager/resource-manager.json +++ b/go-libp2p/dashboards/resource-manager/resource-manager.json @@ -1821,7 +1821,7 @@ }, "timepicker": {}, "timezone": "", - "title": "libp2p Resource Manager", + "title": "go-libp2p Resource Manager", "uid": "MgmGIjjnj", "version": 1, "weekStart": "" diff --git a/go-libp2p/dashboards/swarm/swarm.json b/go-libp2p/dashboards/swarm/swarm.json index ec64784..d206de2 100644 --- a/go-libp2p/dashboards/swarm/swarm.json +++ b/go-libp2p/dashboards/swarm/swarm.json @@ -232,9 +232,7 @@ "options": { "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1139,9 +1137,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1816,9 +1812,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2016,9 +2010,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2110,9 +2102,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2205,9 +2195,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2251,7 +2239,113 @@ }, "mappings": [] }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "canceled: concurrent dial successful" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "application canceled" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "canceled: other" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "timeout" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "other" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "deadline" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "connection refused" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] }, "gridPos": { "h": 8, @@ -2261,16 +2355,16 @@ }, "id": 15, "options": { + "displayLabels": [], "legend": { - "displayMode": "list", + "displayMode": "table", "placement": "right", - "showLegend": true + "showLegend": true, + "values": ["percent"] }, "pieType": "donut", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2542,9 +2636,7 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2688,22 +2780,16 @@ }, "id": 38, "options": { - "displayLabels": [ - "percent" - ], + "displayLabels": ["percent"], "legend": { "displayMode": "table", "placement": "right", "showLegend": true, - "values": [ - "percent" - ] + "values": ["percent"] }, "pieType": "donut", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -2795,7 +2881,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"inf\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.75\"}[$__range]))", + "expr": "sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"+Inf\"}[$__range])) - ignoring(le) sum(increase(libp2p_swarm_dial_ranking_delay_seconds_bucket{instance=~\"$instance\",le=\"0.75\"}[$__range]))", "hide": false, "legendFormat": ">750ms", "range": true, @@ -2926,23 +3012,16 @@ }, "id": 42, "options": { - "displayLabels": [ - "percent", - "name" - ], + "displayLabels": ["percent", "name"], "legend": { "displayMode": "table", "placement": "right", "showLegend": true, - "values": [ - "percent" - ] + "values": ["percent"] }, "pieType": "donut", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -3186,15 +3265,13 @@ "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, "textMode": "value_and_name" }, - "pluginVersion": "9.3.6", + "pluginVersion": "10.0.1", "targets": [ { "datasource": { @@ -3222,7 +3299,7 @@ "mode": "thresholds" }, "mappings": [], - "max": 10, + "max": 100, "min": 0, "thresholds": { "mode": "absolute", @@ -3250,16 +3327,14 @@ "options": { "orientation": "vertical", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, "showThresholdLabels": false, "showThresholdMarkers": true }, - "pluginVersion": "9.3.6", + "pluginVersion": "10.0.1", "targets": [ { "datasource": { @@ -3275,12 +3350,12 @@ "refId": "A" } ], - "title": "Black Hole Filter Success Percentage", + "title": "Dial Success Rate", "type": "gauge" } ], - "refresh": false, - "schemaVersion": 37, + "refresh": "", + "schemaVersion": 38, "style": "dark", "tags": [], "templating": { @@ -3312,7 +3387,6 @@ "refId": "StandardVariableQuery" }, "refresh": 1, - "regex": "", "skipUrlSync": false, "sort": 0, "type": "query" @@ -3320,13 +3394,13 @@ ] }, "time": { - "from": "now-1h", + "from": "now-15m", "to": "now" }, "timepicker": {}, "timezone": "", - "title": "libp2p Swarm", + "title": "go-libp2p Swarm", "uid": "a15PyhO4z", - "version": 7, + "version": 4, "weekStart": "" } diff --git a/go-libp2p/defaults.go b/go-libp2p/defaults.go index c0ed669..8f7dc94 100644 --- a/go-libp2p/defaults.go +++ b/go-libp2p/defaults.go @@ -27,8 +27,8 @@ import ( // Useful when you want to extend, but not replace, the supported transport // security protocols. var DefaultSecurity = ChainOptions( - Security(noise.ID, noise.New), Security(tls.ID, tls.New), + Security(noise.ID, noise.New), ) // DefaultMuxers configures libp2p to use the stream connection multiplexers. @@ -79,11 +79,9 @@ var RandomIdentity = func(cfg *Config) error { var DefaultListenAddrs = func(cfg *Config) error { addrs := []string{ "/ip4/0.0.0.0/tcp/0", - "/ip4/0.0.0.0/udp/0/quic", "/ip4/0.0.0.0/udp/0/quic-v1", "/ip4/0.0.0.0/udp/0/quic-v1/webtransport", "/ip6/::/tcp/0", - "/ip6/::/udp/0/quic", "/ip6/::/udp/0/quic-v1", "/ip6/::/udp/0/quic-v1/webtransport", } diff --git a/go-libp2p/docs/flaky-tests.md b/go-libp2p/docs/flaky-tests.md index e65800a..667dd77 100644 --- a/go-libp2p/docs/flaky-tests.md +++ b/go-libp2p/docs/flaky-tests.md @@ -28,7 +28,7 @@ processes are vying for CPU time. sudo cgset -r cpu.cfs_quota_us=10000 cpulimit sudo cgset -r cpu.cfs_period_us=1000000 cpulimit - # Run a shell with in our limited environemnt + # Run a shell with in our limited environment sudo cgexec -g cpu:cpulimit bash # In the shell, run the test diff --git a/go-libp2p/examples/README.md b/go-libp2p/examples/README.md index 7930ff7..f9074de 100644 --- a/go-libp2p/examples/README.md +++ b/go-libp2p/examples/README.md @@ -2,17 +2,21 @@ In this folder, you can find a variety of examples to help you get started in using go-libp2p. Every example as a specific purpose and some of each incorporate a full tutorial that you can follow through, helping you expand your knowledge about libp2p and p2p networks in general. -Let us know if you find any issue or if you want to contribute and add a new tutorial, feel welcome to submit a pr, thank you! +Let us know if you find any issue or if you want to contribute and add a new tutorial, feel welcome to submit a PR, thank you! ## Examples and Tutorials - [The libp2p 'host'](./libp2p-host) - [Building an http proxy with libp2p](./http-proxy) - [An echo host](./echo) +- [Routed echo host](./routed-echo/) - [Multicodecs with protobufs](./multipro) +- [Relay-based P2P Communication](./relay/) - [P2P chat application](./chat) - [P2P chat application w/ rendezvous peer discovery](./chat-with-rendezvous) - [P2P chat application with peer discovery using mdns](./chat-with-mdns) +- [P2P chat using pubsub](./pubsub) - [A chapter based approach to building a libp2p application](./ipfs-camp-2019/) _Created for [IPFS Camp 2019](https://github.com/ipfs/camp/tree/master/CORE_AND_ELECTIVE_COURSES/CORE_COURSE_B)_ +- [View metrics using Prometheus and Grafana](./metrics-and-dashboards) -For js-libp2p examples, check https://github.com/libp2p/js-libp2p/tree/master/examples +For js-libp2p examples, check https://github.com/libp2p/js-libp2p-examples diff --git a/go-libp2p/examples/chat-with-mdns/README.md b/go-libp2p/examples/chat-with-mdns/README.md index 836fb7a..8e467e6 100644 --- a/go-libp2p/examples/chat-with-mdns/README.md +++ b/go-libp2p/examples/chat-with-mdns/README.md @@ -57,29 +57,37 @@ func handleStream(stream net.Stream) { 3. **Find peers nearby using mdns** -Start [mdns discovery](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery#NewMdnsService) service in host. +New [mdns discovery](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery#NewMdnsService) service in host. ```go -ser, err := discovery.NewMdnsService(peerhost, rendezvous) +notifee := &discoveryNotifee{PeerChan: make(chan peer.AddrInfo)} +ser, err := discovery.NewMdnsService(peerhost, rendezvous, notifee) ``` register [Notifee interface](https://godoc.org/github.com/libp2p/go-libp2p/p2p/discovery#Notifee) with service so that we get notified about peer discovery ```go - n := &discoveryNotifee{} - ser.RegisterNotifee(n) + ser.Start() ``` + 4. **Open streams to peers found.** Finally we open stream to the peers we found, as we find them ```go peer := <-peerChan // will block until we discover a peer + // this is used to avoid call `NewStream` from both side + if peer.ID > host.ID() { + // if other end peer id greater than us, don't connect to it, just wait for it to connect us + fmt.Println("Found peer:", peer, " id is greater than us, wait for it to connect to us") + continue + } fmt.Println("Found peer:", peer, ", connecting") if err := host.Connect(ctx, peer); err != nil { fmt.Println("Connection failed:", err) + continue } // open a stream, this stream will be handled by handleStream other end diff --git a/go-libp2p/examples/chat-with-mdns/main.go b/go-libp2p/examples/chat-with-mdns/main.go index 57b89c2..55c36ad 100644 --- a/go-libp2p/examples/chat-with-mdns/main.go +++ b/go-libp2p/examples/chat-with-mdns/main.go @@ -111,11 +111,16 @@ func main() { // This function is called when a peer initiates a connection and starts a stream with this peer. host.SetStreamHandler(protocol.ID(cfg.ProtocolID), handleStream) - fmt.Printf("\n[*] Your Multiaddress Is: /ip4/%s/tcp/%v/p2p/%s\n", cfg.listenHost, cfg.listenPort, host.ID().Pretty()) + fmt.Printf("\n[*] Your Multiaddress Is: /ip4/%s/tcp/%v/p2p/%s\n", cfg.listenHost, cfg.listenPort, host.ID()) peerChan := initMDNS(host, cfg.RendezvousString) for { // allows multiple peers to join peer := <-peerChan // will block until we discover a peer + if peer.ID > host.ID() { + // if other end peer id greater than us, don't connect to it, just wait for it to connect us + fmt.Println("Found peer:", peer, " id is greater than us, wait for it to connect to us") + continue + } fmt.Println("Found peer:", peer, ", connecting") if err := host.Connect(ctx, peer); err != nil { diff --git a/go-libp2p/examples/chat-with-rendezvous/chat.go b/go-libp2p/examples/chat-with-rendezvous/chat.go index 5fc8d4e..a2ddb89 100644 --- a/go-libp2p/examples/chat-with-rendezvous/chat.go +++ b/go-libp2p/examples/chat-with-rendezvous/chat.go @@ -6,7 +6,7 @@ import ( "flag" "fmt" "os" - "sync" + "time" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/network" @@ -114,7 +114,12 @@ func main() { // DHT, so that the bootstrapping node of the DHT can go down without // inhibiting future peer discovery. ctx := context.Background() - kademliaDHT, err := dht.New(ctx, host) + bootstrapPeers := make([]peer.AddrInfo, len(config.BootstrapPeers)) + for i, addr := range config.BootstrapPeers { + peerinfo, _ := peer.AddrInfoFromP2pAddr(addr) + bootstrapPeers[i] = *peerinfo + } + kademliaDHT, err := dht.New(ctx, host, dht.BootstrapPeers(bootstrapPeers...)) if err != nil { panic(err) } @@ -126,22 +131,8 @@ func main() { panic(err) } - // Let's connect to the bootstrap nodes first. They will tell us about the - // other nodes in the network. - var wg sync.WaitGroup - for _, peerAddr := range config.BootstrapPeers { - peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr) - wg.Add(1) - go func() { - defer wg.Done() - if err := host.Connect(ctx, *peerinfo); err != nil { - logger.Warning(err) - } else { - logger.Info("Connection established with bootstrap node:", *peerinfo) - } - }() - } - wg.Wait() + // Wait a bit to let bootstrapping finish (really bootstrap should block until it's ready, but that isn't the case yet.) + time.Sleep(1 * time.Second) // We use a rendezvous point "meet me here" to announce our location. // This is like telling your friends to meet you at the Eiffel Tower. diff --git a/go-libp2p/examples/chat/chat.go b/go-libp2p/examples/chat/chat.go index cd1c287..d89ea3c 100644 --- a/go-libp2p/examples/chat/chat.go +++ b/go-libp2p/examples/chat/chat.go @@ -187,7 +187,7 @@ func startPeer(ctx context.Context, h host.Host, streamHandler network.StreamHan return } - log.Printf("Run './chat -d /ip4/127.0.0.1/tcp/%v/p2p/%s' on another console.\n", port, h.ID().Pretty()) + log.Printf("Run './chat -d /ip4/127.0.0.1/tcp/%v/p2p/%s' on another console.\n", port, h.ID()) log.Println("You can replace 127.0.0.1 with public IP as well.") log.Println("Waiting for incoming connection") log.Println() diff --git a/go-libp2p/examples/chat/chat_test.go b/go-libp2p/examples/chat/chat_test.go index 1a1cea3..4240b47 100644 --- a/go-libp2p/examples/chat/chat_test.go +++ b/go-libp2p/examples/chat/chat_test.go @@ -49,7 +49,7 @@ func TestMain(t *testing.T) { cancel() // end the test }) - dest := fmt.Sprintf("/ip4/127.0.0.1/tcp/%v/p2p/%s", port1, h1.ID().Pretty()) + dest := fmt.Sprintf("/ip4/127.0.0.1/tcp/%v/p2p/%s", port1, h1.ID()) h2, err := makeHost(port2, rand.Reader) if err != nil { diff --git a/go-libp2p/examples/echo/README.md b/go-libp2p/examples/echo/README.md index 3807160..4c30609 100644 --- a/go-libp2p/examples/echo/README.md +++ b/go-libp2p/examples/echo/README.md @@ -42,7 +42,7 @@ The `makeBasicHost()` function creates a [go-libp2p-basichost](https://godoc.org In order to create the swarm (and a `basichost`), the example needs: -- An [ipfs-procotol ID](https://godoc.org/github.com/libp2p/go-libp2p-peer#ID) like `QmNtX1cvrm2K6mQmMEaMxAuB4rTexhd87vpYVot4sEZzxc`. The example autogenerates a key pair on every run and uses an ID extracted from the public key (the hash of the public key). When using `-insecure`, it leaves the connection unencrypted (otherwise, it uses the key pair to encrypt communications). +- An [ipfs-protocol ID](https://godoc.org/github.com/libp2p/go-libp2p-peer#ID) like `QmNtX1cvrm2K6mQmMEaMxAuB4rTexhd87vpYVot4sEZzxc`. The example autogenerates a key pair on every run and uses an ID extracted from the public key (the hash of the public key). When using `-insecure`, it leaves the connection unencrypted (otherwise, it uses the key pair to encrypt communications). - A [Multiaddress](https://godoc.org/github.com/multiformats/go-multiaddr), which indicates how to reach this peer. There can be several of them (using different protocols or locations for example). Example: `/ip4/127.0.0.1/tcp/1234`. - A [go-libp2p-peerstore](https://godoc.org/github.com/libp2p/go-libp2p-peerstore), which is used as an address book which matches node IDs to the multiaddresses through which they can be contacted. This peerstore gets autopopulated when manually opening a connection (with [`Connect()`](https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#BasicHost.Connect). Alternatively, we can manually [`AddAddr()`](https://godoc.org/github.com/libp2p/go-libp2p-peerstore#AddrManager.AddAddr) as in the example. diff --git a/go-libp2p/examples/echo/main.go b/go-libp2p/examples/echo/main.go index 3bba896..90c7248 100644 --- a/go-libp2p/examples/echo/main.go +++ b/go-libp2p/examples/echo/main.go @@ -88,7 +88,7 @@ func makeBasicHost(listenPort int, insecure bool, randseed int64) (host.Host, er func getHostAddress(ha host.Host) string { // Build host multiaddress - hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", ha.ID().Pretty())) + hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", ha.ID())) // Now we can build a full multiaddress to reach this host // by encapsulating both addresses: @@ -125,18 +125,6 @@ func runSender(ctx context.Context, ha host.Host, targetPeer string) { fullAddr := getHostAddress(ha) log.Printf("I am %s\n", fullAddr) - // Set a stream handler on host A. /echo/1.0.0 is - // a user-defined protocol name. - ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) { - log.Println("sender received new stream") - if err := doEcho(s); err != nil { - log.Println(err) - s.Reset() - } else { - s.Close() - } - }) - // Turn the targetPeer into a multiaddr. maddr, err := ma.NewMultiaddr(targetPeer) if err != nil { diff --git a/go-libp2p/examples/go.mod b/go-libp2p/examples/go.mod index feb9b15..578546a 100644 --- a/go-libp2p/examples/go.mod +++ b/go-libp2p/examples/go.mod @@ -1,16 +1,16 @@ module github.com/libp2p/go-libp2p/examples -go 1.19 +go 1.21 require ( github.com/gogo/protobuf v1.3.2 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.4.0 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-log/v2 v2.5.1 - github.com/libp2p/go-libp2p v0.29.0 - github.com/libp2p/go-libp2p-kad-dht v0.20.1-0.20230209220319-6c2045abad23 - github.com/multiformats/go-multiaddr v0.10.1 - github.com/prometheus/client_golang v1.14.0 + github.com/libp2p/go-libp2p v0.33.0 + github.com/libp2p/go-libp2p-kad-dht v0.25.1 + github.com/multiformats/go-multiaddr v0.12.2 + github.com/prometheus/client_golang v1.18.0 ) require ( @@ -23,46 +23,45 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/boxo v0.10.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.2.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipld/go-ipld-prime v0.16.0 // indirect + github.com/ipld/go-ipld-prime v0.20.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/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect - github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.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/zeroconf/v2 v2.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // 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 @@ -74,39 +73,41 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/polydawn/refmt v0.89.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.36.2 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.41.0 // indirect + github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.20.0 // indirect + go.opentelemetry.io/otel v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.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/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - golang.org/x/tools v0.11.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.18.0 // indirect + gonum.org/v1/gonum v0.13.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go-libp2p/examples/go.sum b/go-libp2p/examples/go.sum index 5ac4751..bae0579 100644 --- a/go-libp2p/examples/go.sum +++ b/go-libp2p/examples/go.sum @@ -33,13 +33,13 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/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/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -54,19 +54,24 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= -github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= 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= @@ -76,13 +81,12 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -93,7 +97,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -104,27 +107,27 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/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.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -134,9 +137,10 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY= +github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= @@ -145,15 +149,13 @@ github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= -github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipld/go-ipld-prime v0.16.0 h1:RS5hhjB/mcpeEPJvfyj0qbOj/QL+/j05heZ0qa97dVo= -github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= +github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g= +github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -169,18 +171,16 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +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/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -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= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -192,25 +192,28 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.29.0 h1:QduJ2XQr/Crg4EnloueWDL0Jj86N3Ezhyyj7XH+XwHI= -github.com/libp2p/go-libp2p v0.29.0/go.mod h1:iNKL7mEnZ9wAss+03IjAwM9ZAQXfVUAPUUmOACQfQ/g= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= -github.com/libp2p/go-libp2p-kad-dht v0.20.1-0.20230209220319-6c2045abad23 h1:VGjUg3I0gLugtjZKI4kzvPiptmfYhWHK6YGBI4ZI2Cs= -github.com/libp2p/go-libp2p-kad-dht v0.20.1-0.20230209220319-6c2045abad23/go.mod h1:ScWrKlutIaRETyELjPNXUO2TekuzLsE5nCBVuNR9l0g= -github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA= -github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U= +github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ= +github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE= +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-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= +github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= +github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= +github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2 h1:xJMFyhQ3Iuqnk9Q2dYE1eUTzsah7NLw3Qs2zjUV78T0= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +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/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= @@ -220,16 +223,14 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -238,55 +239,46 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= -github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.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= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/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/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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= @@ -297,36 +289,32 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= +github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.36.2 h1:ZX/UNQ4gvpCv2RmwdbA6lrRjF6EBm5yZ7TMoT4NQVrA= -github.com/quic-go/quic-go v0.36.2/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= +github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= +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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -354,10 +342,10 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -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/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -374,13 +362,14 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -389,16 +378,25 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= -go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.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/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -406,8 +404,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -418,13 +416,12 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-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.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -436,8 +433,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -456,8 +453,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -471,8 +468,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -486,7 +483,6 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -494,16 +490,15 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -522,14 +517,15 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= +gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -561,10 +557,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -586,7 +580,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/go-libp2p/examples/http-proxy/proxy.go b/go-libp2p/examples/http-proxy/proxy.go index 27d9597..f96d4b8 100644 --- a/go-libp2p/examples/http-proxy/proxy.go +++ b/go-libp2p/examples/http-proxy/proxy.go @@ -144,7 +144,7 @@ func (p *ProxyService) Serve() { // Streams are multiplexed over single connections so, unlike connections // themselves, they are cheap to create and dispose of. func (p *ProxyService) ServeHTTP(w http.ResponseWriter, r *http.Request) { - fmt.Printf("proxying request for %s to peer %s\n", r.URL, p.dest.Pretty()) + fmt.Printf("proxying request for %s to peer %s\n", r.URL, p.dest) // We need to send the request to the remote libp2p peer, so // we open a stream to it stream, err := p.host.NewStream(context.Background(), p.dest, Protocol) diff --git a/go-libp2p/examples/ipfs-camp-2019/05-Discovery/main.go b/go-libp2p/examples/ipfs-camp-2019/05-Discovery/main.go index 51d5a6f..0f3446d 100644 --- a/go-libp2p/examples/ipfs-camp-2019/05-Discovery/main.go +++ b/go-libp2p/examples/ipfs-camp-2019/05-Discovery/main.go @@ -9,7 +9,6 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" tls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/tcp" @@ -27,10 +26,7 @@ func main() { libp2p.Transport(websocket.New), ) - muxers := libp2p.ChainOptions( - libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), - libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), - ) + muxers := libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport) security := libp2p.Security(tls.ID, tls.New) diff --git a/go-libp2p/examples/ipfs-camp-2019/06-Pubsub/main.go b/go-libp2p/examples/ipfs-camp-2019/06-Pubsub/main.go index 9034541..af7cab2 100644 --- a/go-libp2p/examples/ipfs-camp-2019/06-Pubsub/main.go +++ b/go-libp2p/examples/ipfs-camp-2019/06-Pubsub/main.go @@ -16,7 +16,6 @@ import ( "github.com/libp2p/go-libp2p/p2p/discovery/mdns" drouting "github.com/libp2p/go-libp2p/p2p/discovery/routing" dutil "github.com/libp2p/go-libp2p/p2p/discovery/util" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" tls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/tcp" @@ -46,10 +45,7 @@ func main() { libp2p.Transport(websocket.New), ) - muxers := libp2p.ChainOptions( - libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), - libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), - ) + muxers := libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport) security := libp2p.Security(tls.ID, tls.New) diff --git a/go-libp2p/examples/ipfs-camp-2019/07-Messaging/main.go b/go-libp2p/examples/ipfs-camp-2019/07-Messaging/main.go index 84840d7..b758e21 100644 --- a/go-libp2p/examples/ipfs-camp-2019/07-Messaging/main.go +++ b/go-libp2p/examples/ipfs-camp-2019/07-Messaging/main.go @@ -9,7 +9,6 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/p2p/discovery/mdns" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" tls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/tcp" @@ -42,10 +41,7 @@ func main() { libp2p.Transport(websocket.New), ) - muxers := libp2p.ChainOptions( - libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), - libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), - ) + muxers := libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport) security := libp2p.Security(tls.ID, tls.New) diff --git a/go-libp2p/examples/ipfs-camp-2019/08-End/main.go b/go-libp2p/examples/ipfs-camp-2019/08-End/main.go index bc29152..e3ef953 100644 --- a/go-libp2p/examples/ipfs-camp-2019/08-End/main.go +++ b/go-libp2p/examples/ipfs-camp-2019/08-End/main.go @@ -14,7 +14,6 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/routing" "github.com/libp2p/go-libp2p/p2p/discovery/mdns" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" tls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/tcp" @@ -41,10 +40,7 @@ func main() { libp2p.Transport(websocket.New), ) - muxers := libp2p.ChainOptions( - libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport), - libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport), - ) + muxers := libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport) security := libp2p.Security(tls.ID, tls.New) diff --git a/go-libp2p/examples/ipfs-camp-2019/go.mod b/go-libp2p/examples/ipfs-camp-2019/go.mod index 2bcabeb..0d0b29c 100644 --- a/go-libp2p/examples/ipfs-camp-2019/go.mod +++ b/go-libp2p/examples/ipfs-camp-2019/go.mod @@ -1,13 +1,13 @@ module github.com/libp2p/go-libp2p/examples/ipfs-camp-2019 -go 1.19 +go 1.21 require ( github.com/gogo/protobuf v1.3.2 - github.com/libp2p/go-libp2p v0.28.0 - github.com/libp2p/go-libp2p-kad-dht v0.21.0 - github.com/libp2p/go-libp2p-pubsub v0.9.0 - github.com/multiformats/go-multiaddr v0.9.0 + github.com/libp2p/go-libp2p v0.33.0 + github.com/libp2p/go-libp2p-kad-dht v0.25.1 + github.com/libp2p/go-libp2p-pubsub v0.10.0 + github.com/multiformats/go-multiaddr v0.12.2 ) require ( @@ -20,52 +20,49 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/boxo v0.10.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.2.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/ipld/go-ipld-prime v0.16.0 // indirect + github.com/ipld/go-ipld-prime v0.20.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/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.16.5 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect - github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect - github.com/libp2p/go-mplex v0.7.0 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.3.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.54 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // 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 @@ -76,41 +73,43 @@ require ( github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect - github.com/multiformats/go-multihash v0.2.2 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.9.7 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/polydawn/refmt v0.89.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.41.0 // indirect + github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.19.2 // indirect + go.opentelemetry.io/otel v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.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/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.9.1 // indirect - google.golang.org/protobuf v1.30.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.18.0 // indirect + gonum.org/v1/gonum v0.13.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go-libp2p/examples/ipfs-camp-2019/go.sum b/go-libp2p/examples/ipfs-camp-2019/go.sum index 23a9792..fecbd95 100644 --- a/go-libp2p/examples/ipfs-camp-2019/go.sum +++ b/go-libp2p/examples/ipfs-camp-2019/go.sum @@ -33,13 +33,13 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/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/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -49,26 +49,29 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= -github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= 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= @@ -78,13 +81,12 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -95,7 +97,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -106,27 +107,27 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/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.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -136,11 +137,12 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= -github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY= +github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= @@ -149,15 +151,13 @@ github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= -github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipld/go-ipld-prime v0.16.0 h1:RS5hhjB/mcpeEPJvfyj0qbOj/QL+/j05heZ0qa97dVo= -github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= +github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g= +github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -173,18 +173,16 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +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/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -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= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -196,31 +194,32 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= -github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= -github.com/libp2p/go-libp2p-kad-dht v0.21.0 h1:J0Yd22VA+sk0CJRGMgtfHvLVIkZDyJ3AJGiljywIw5U= -github.com/libp2p/go-libp2p-kad-dht v0.21.0/go.mod h1:Bhm9diAFmc6qcWAr084bHNL159srVZRKADdp96Qqd1I= -github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA= -github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U= -github.com/libp2p/go-libp2p-pubsub v0.9.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s= -github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7bMZwHP+6vNMd+c7I= +github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ= +github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE= +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-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= +github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= +github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= +github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= +github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= +github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2 h1:xJMFyhQ3Iuqnk9Q2dYE1eUTzsah7NLw3Qs2zjUV78T0= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= -github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= -github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/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/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= @@ -228,16 +227,14 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -246,55 +243,46 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= -github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= -github.com/multiformats/go-multihash v0.2.2/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-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-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= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/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/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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= @@ -305,36 +293,32 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= +github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= -github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= +github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= +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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -362,10 +346,10 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -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/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -381,14 +365,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -397,16 +382,25 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +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/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -414,8 +408,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -426,13 +420,12 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -444,8 +437,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -464,8 +457,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -479,8 +472,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -494,7 +487,6 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -502,16 +494,15 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -530,14 +521,15 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= +gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -569,10 +561,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -594,7 +584,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/go-libp2p/examples/libp2p-host/README.md b/go-libp2p/examples/libp2p-host/README.md index e187f06..966ee0e 100644 --- a/go-libp2p/examples/libp2p-host/README.md +++ b/go-libp2p/examples/libp2p-host/README.md @@ -84,7 +84,7 @@ defer h2.Close() fmt.Printf("Hello World, my second hosts ID is %s\n", h2.ID()) ``` -And thats it, you have a libp2p host and you're ready to start doing some awesome p2p networking! +And that's it, you have a libp2p host and you're ready to start doing some awesome p2p networking! In future guides we will go over ways to use hosts, configure them differently (hint: there are a huge number of ways to set these up), and interesting ways to apply this technology to various applications you might want to build. diff --git a/go-libp2p/examples/multipro/pb/p2p.pb.go b/go-libp2p/examples/multipro/pb/p2p.pb.go index a33d549..2399383 100644 --- a/go-libp2p/examples/multipro/pb/p2p.pb.go +++ b/go-libp2p/examples/multipro/pb/p2p.pb.go @@ -110,7 +110,7 @@ func (m *MessageData) GetSign() []byte { return nil } -// a protocol define a set of reuqest and responses +// A protocol defines a set of requests and responses. type PingRequest struct { MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` // method specific data @@ -205,7 +205,7 @@ func (m *PingResponse) GetMessage() string { return "" } -// a protocol define a set of reuqest and responses +// A protocol defines a set of requests and responses type EchoRequest struct { MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData" json:"messageData,omitempty"` // method specific data diff --git a/go-libp2p/examples/multipro/pb/p2p.proto b/go-libp2p/examples/multipro/pb/p2p.proto index 5488f2a..a360b24 100644 --- a/go-libp2p/examples/multipro/pb/p2p.proto +++ b/go-libp2p/examples/multipro/pb/p2p.proto @@ -16,7 +16,7 @@ message MessageData { //// ping protocol -// a protocol define a set of reuqest and responses +// A protocol defines a set of requests and responses. message PingRequest { MessageData messageData = 1; @@ -36,7 +36,7 @@ message PingResponse { //// echo protocol -// a protocol define a set of reuqest and responses +// A protocol defines a set of requests and responses. message EchoRequest { MessageData messageData = 1; diff --git a/go-libp2p/examples/pubsub/README.md b/go-libp2p/examples/pubsub/README.md index 050b33f..a41419a 100644 --- a/go-libp2p/examples/pubsub/README.md +++ b/go-libp2p/examples/pubsub/README.md @@ -3,4 +3,5 @@ This directory contains example projects that use [go-libp2p-pubsub](https://github.com/libp2p/go-libp2p-pubsub), the Go implementation of libp2p's [Publish / Subscribe system](https://docs.libp2p.io/concepts/publish-subscribe). -The [chat room example](./chat) covers the basics of using the PubSub API to build a peer-to-peer chat application. +- The [chat room example](./chat) covers the basics of using the PubSub API to build a peer-to-peer chat application. +- The [pubsub rendezvous example](./basic-chat-with-rendezvous) allows multiple peers to chat among each other using go-libp2p-pubsub using rendezvous names. diff --git a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.mod b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.mod index f9cf1ec..cd90b4d 100644 --- a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.mod +++ b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.mod @@ -1,11 +1,11 @@ module github.com/libp2p/go-libp2p/examples/pubsub/chat -go 1.19 +go 1.21 require ( - github.com/libp2p/go-libp2p v0.28.0 - github.com/libp2p/go-libp2p-kad-dht v0.21.0 - github.com/libp2p/go-libp2p-pubsub v0.9.0 + github.com/libp2p/go-libp2p v0.33.0 + github.com/libp2p/go-libp2p-kad-dht v0.25.1 + github.com/libp2p/go-libp2p-pubsub v0.10.0 ) require ( @@ -18,97 +18,97 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/ipfs/boxo v0.10.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.2.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/ipld/go-ipld-prime v0.9.0 // indirect + github.com/ipld/go-ipld-prime v0.20.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/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.16.5 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect - github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.3.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.54 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr v0.9.0 // indirect + github.com/multiformats/go-multiaddr v0.12.2 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect - github.com/multiformats/go-multihash v0.2.2 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.9.7 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/polydawn/refmt v0.89.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.41.0 // indirect + github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.19.2 // indirect + go.opentelemetry.io/otel v1.16.0 // indirect + go.opentelemetry.io/otel/metric v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.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/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.9.1 // indirect - google.golang.org/protobuf v1.30.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.18.0 // indirect + gonum.org/v1/gonum v0.13.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.sum b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.sum index 8a766f9..826d9e2 100644 --- a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.sum +++ b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/go.sum @@ -39,6 +39,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/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/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -48,25 +49,29 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= 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= @@ -76,13 +81,12 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -93,7 +97,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -104,27 +107,27 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -134,11 +137,12 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= -github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY= +github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= @@ -147,15 +151,13 @@ github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU= -github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipld/go-ipld-prime v0.9.0 h1:N2OjJMb+fhyFPwPnVvJcWU/NsumP8etal+d2v3G4eww= -github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= +github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g= +github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -171,63 +173,65 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +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/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= -github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= -github.com/libp2p/go-libp2p-kad-dht v0.21.0 h1:J0Yd22VA+sk0CJRGMgtfHvLVIkZDyJ3AJGiljywIw5U= -github.com/libp2p/go-libp2p-kad-dht v0.21.0/go.mod h1:Bhm9diAFmc6qcWAr084bHNL159srVZRKADdp96Qqd1I= -github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA= -github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U= -github.com/libp2p/go-libp2p-pubsub v0.9.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s= -github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7bMZwHP+6vNMd+c7I= +github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ= +github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE= +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-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= +github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= +github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= +github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= +github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= +github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2 h1:xJMFyhQ3Iuqnk9Q2dYE1eUTzsah7NLw3Qs2zjUV78T0= +github.com/libp2p/go-libp2p-routing-helpers v0.7.2/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -236,54 +240,46 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= -github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= -github.com/multiformats/go-multihash v0.2.2/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-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-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= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/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/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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= @@ -294,34 +290,32 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= -github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= +github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= -github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= +github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= +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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -349,10 +343,10 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -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/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -368,13 +362,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -383,16 +379,25 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +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/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -400,8 +405,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -412,13 +417,12 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -430,8 +434,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -449,8 +453,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -464,8 +468,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -479,21 +483,19 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -512,14 +514,15 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= +gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -551,10 +554,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -564,6 +565,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/main.go b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/main.go index 57729ed..46d8ca0 100644 --- a/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/main.go +++ b/go-libp2p/examples/pubsub/basic-chat-with-rendezvous/main.go @@ -95,9 +95,9 @@ func discoverPeers(ctx context.Context, h host.Host) { } err := h.Connect(ctx, peer) if err != nil { - fmt.Println("Failed connecting to ", peer.ID.Pretty(), ", error:", err) + fmt.Printf("Failed connecting to %s, error: %s\n", peer.ID, err) } else { - fmt.Println("Connected to:", peer.ID.Pretty()) + fmt.Println("Connected to:", peer.ID) anyConnected = true } } diff --git a/go-libp2p/examples/pubsub/chat/README.md b/go-libp2p/examples/pubsub/chat/README.md index 2b99c12..a37af70 100644 --- a/go-libp2p/examples/pubsub/chat/README.md +++ b/go-libp2p/examples/pubsub/chat/README.md @@ -132,7 +132,7 @@ to the `pubsub.Topic`: func (cr *ChatRoom) Publish(message string) error { m := ChatMessage{ Message: message, - SenderID: cr.self.Pretty(), + SenderID: cr.self.String(), SenderNick: cr.nick, } msgBytes, err := json.Marshal(m) diff --git a/go-libp2p/examples/pubsub/chat/chatroom.go b/go-libp2p/examples/pubsub/chat/chatroom.go index 452cc30..dc323d5 100644 --- a/go-libp2p/examples/pubsub/chat/chatroom.go +++ b/go-libp2p/examples/pubsub/chat/chatroom.go @@ -71,7 +71,7 @@ func JoinChatRoom(ctx context.Context, ps *pubsub.PubSub, selfID peer.ID, nickna func (cr *ChatRoom) Publish(message string) error { m := ChatMessage{ Message: message, - SenderID: cr.self.Pretty(), + SenderID: cr.self.String(), SenderNick: cr.nick, } msgBytes, err := json.Marshal(m) diff --git a/go-libp2p/examples/pubsub/chat/go.mod b/go-libp2p/examples/pubsub/chat/go.mod index 11b1eb1..6c53916 100644 --- a/go-libp2p/examples/pubsub/chat/go.mod +++ b/go-libp2p/examples/pubsub/chat/go.mod @@ -1,11 +1,11 @@ module github.com/libp2p/go-libp2p/examples/pubsub/chat -go 1.19 +go 1.21 require ( github.com/gdamore/tcell/v2 v2.5.2 - github.com/libp2p/go-libp2p v0.28.0 - github.com/libp2p/go-libp2p-pubsub v0.9.0 + github.com/libp2p/go-libp2p v0.33.0 + github.com/libp2p/go-libp2p-pubsub v0.10.0 github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 ) @@ -19,89 +19,80 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/gdamore/encoding v1.0.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/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.16.5 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.3.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.54 // indirect + github.com/miekg/dns v1.1.58 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr v0.9.0 // indirect + github.com/multiformats/go-multiaddr v0.12.2 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect - github.com/multiformats/go-multihash v0.2.2 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.9.7 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.41.0 // indirect + github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.19.2 // 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/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.9.1 // indirect - google.golang.org/protobuf v1.30.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.18.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go-libp2p/examples/pubsub/chat/go.sum b/go-libp2p/examples/pubsub/chat/go.sum index e9d38f1..fa89b78 100644 --- a/go-libp2p/examples/pubsub/chat/go.sum +++ b/go-libp2p/examples/pubsub/chat/go.sum @@ -37,6 +37,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/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/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -46,11 +47,9 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -62,7 +61,8 @@ github.com/gdamore/tcell/v2 v2.5.2/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tv github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -77,45 +77,36 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= -github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= -github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= -github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -128,42 +119,43 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +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/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.28.0 h1:zO8cY98nJiPzZpFv5w5gqqb8aVzt4ukQ0nVOSaaKhJ8= -github.com/libp2p/go-libp2p v0.28.0/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= -github.com/libp2p/go-libp2p-pubsub v0.9.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s= -github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7bMZwHP+6vNMd+c7I= +github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ= +github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= +github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/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/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -173,18 +165,16 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -206,8 +196,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -217,22 +207,22 @@ github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6o github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.2.2 h1:Uu7LWs/PmWby1gkj1S1DXx3zyd3aVabA4FiMKn/2tAc= -github.com/multiformats/go-multihash v0.2.2/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-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-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/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/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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= @@ -242,34 +232,31 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= -github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= +github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= +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/rivo/tview v0.0.0-20220307222120-9994674d60a8 h1:xe+mmCnDN82KhC010l3NfYlA8ZbOuzbXAzSYBa6wbMc= github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8/go.mod h1:WIfMkQNY+oq/mWwtsjOYHIZBuwthioY2srOmljJkTnk= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -307,7 +294,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= @@ -316,53 +304,50 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +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/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= +golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -380,8 +365,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -395,8 +380,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -419,20 +404,20 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -442,17 +427,13 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -473,15 +454,12 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -489,11 +467,11 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/go-libp2p/examples/pubsub/chat/main.go b/go-libp2p/examples/pubsub/chat/main.go index 45a103d..593e41e 100644 --- a/go-libp2p/examples/pubsub/chat/main.go +++ b/go-libp2p/examples/pubsub/chat/main.go @@ -80,7 +80,7 @@ func defaultNick(p peer.ID) string { // shortID returns the last 8 chars of a base58-encoded peer id. func shortID(p peer.ID) string { - pretty := p.Pretty() + pretty := p.String() return pretty[len(pretty)-8:] } @@ -93,10 +93,10 @@ type discoveryNotifee struct { // the PubSub system will automatically start interacting with them if they also // support PubSub. func (n *discoveryNotifee) HandlePeerFound(pi peer.AddrInfo) { - fmt.Printf("discovered new peer %s\n", pi.ID.Pretty()) + fmt.Printf("discovered new peer %s\n", pi.ID) err := n.h.Connect(context.Background(), pi) if err != nil { - fmt.Printf("error connecting to peer %s: %s\n", pi.ID.Pretty(), err) + fmt.Printf("error connecting to peer %s: %s\n", pi.ID, err) } } diff --git a/go-libp2p/examples/relay/README.md b/go-libp2p/examples/relay/README.md new file mode 100644 index 0000000..a4bd5c5 --- /dev/null +++ b/go-libp2p/examples/relay/README.md @@ -0,0 +1,15 @@ +# Relay-based P2P Communication Example + +## Overview +This project demonstrates the setup of a relay-based peer-to-peer communication using the libp2p library in Go. It features creating unreachable libp2p hosts and facilitating their communication through a relay node. + +## Features +- Creation of two "unreachable" libp2p hosts. +- Setup of a relay node to enable communication between these hosts. + +## Usage + +Run the program + ```bash + go run . + ``` \ No newline at end of file diff --git a/go-libp2p/examples/relay/main.go b/go-libp2p/examples/relay/main.go index e8fa8b7..7e16b1b 100644 --- a/go-libp2p/examples/relay/main.go +++ b/go-libp2p/examples/relay/main.go @@ -27,7 +27,7 @@ func run() { unreachable1, err := libp2p.New( libp2p.NoListenAddrs, // Usually EnableRelay() is not required as it is enabled by default - // but NoListenAddrs overrides this, so we're adding it in explictly again. + // but NoListenAddrs overrides this, so we're adding it in explicitly again. libp2p.EnableRelay(), ) if err != nil { diff --git a/go-libp2p/examples/routed-echo/main.go b/go-libp2p/examples/routed-echo/main.go index 2f40549..342661b 100644 --- a/go-libp2p/examples/routed-echo/main.go +++ b/go-libp2p/examples/routed-echo/main.go @@ -83,7 +83,7 @@ func makeRoutedHost(listenPort int, randseed int64, bootstrapPeers []peer.AddrIn } // Build host multiaddress - hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", routedHost.ID().Pretty())) + hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", routedHost.ID())) // Now we can build a full multiaddress to reach this host // by encapsulating both addresses: @@ -94,7 +94,7 @@ func makeRoutedHost(listenPort int, randseed int64, bootstrapPeers []peer.AddrIn log.Println(addr.Encapsulate(hostAddr)) } - log.Printf("Now run \"./routed-echo -l %d -d %s%s\" on a different terminal\n", listenPort+1, routedHost.ID().Pretty(), globalFlag) + log.Printf("Now run \"./routed-echo -l %d -d %s%s\" on a different terminal\n", listenPort+1, routedHost.ID(), globalFlag) return routedHost, nil } diff --git a/go-libp2p/go.mod b/go-libp2p/go.mod index 980dd8a..bff7698 100644 --- a/go-libp2p/go.mod +++ b/go-libp2p/go.mod @@ -1,64 +1,69 @@ module github.com/libp2p/go-libp2p -go 1.19 +go 1.21 retract v0.26.1 // Tag was applied incorrectly due to a bug in the release workflow. require ( github.com/benbjohnson/clock v1.3.5 github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 - github.com/flynn/noise v1.0.0 - github.com/golang/mock v1.6.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 + github.com/flynn/noise v1.1.0 github.com/google/gopacket v1.1.19 - github.com/gorilla/websocket v1.5.0 - github.com/hashicorp/golang-lru/v2 v2.0.2 + github.com/gorilla/websocket v1.5.1 + github.com/hashicorp/golang-lru/arc/v2 v2.0.7 + github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger v0.3.0 github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/jbenet/go-temp-err-catcher v0.1.0 - github.com/klauspost/compress v1.16.7 + github.com/klauspost/compress v1.17.8 github.com/libp2p/go-buffer-pool v0.1.0 github.com/libp2p/go-flow-metrics v0.1.0 - github.com/libp2p/go-libp2p-asn-util v0.3.0 + github.com/libp2p/go-libp2p-asn-util v0.4.1 github.com/libp2p/go-libp2p-testing v0.12.0 - github.com/libp2p/go-mplex v0.7.0 github.com/libp2p/go-msgio v0.3.0 github.com/libp2p/go-nat v0.2.0 github.com/libp2p/go-netroute v0.2.1 - github.com/libp2p/go-reuseport v0.3.0 + github.com/libp2p/go-reuseport v0.4.0 github.com/libp2p/go-yamux/v4 v4.0.1 github.com/libp2p/zeroconf/v2 v2.2.0 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b - github.com/minio/sha256-simd v1.0.1 github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.10.1 + github.com/multiformats/go-multiaddr v0.12.4 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multiaddr-fmt v0.1.0 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-multicodec v0.9.0 github.com/multiformats/go-multihash v0.2.3 - github.com/multiformats/go-multistream v0.4.1 + github.com/multiformats/go-multistream v0.5.0 github.com/multiformats/go-varint v0.0.7 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 - github.com/prometheus/client_golang v1.14.0 - github.com/prometheus/client_model v0.4.0 - github.com/quic-go/quic-go v0.36.3 - github.com/quic-go/webtransport-go v0.5.3 + github.com/pion/datachannel v1.5.6 + github.com/pion/ice/v2 v2.3.24 + github.com/pion/logging v0.2.2 + github.com/pion/sctp v1.8.16 + github.com/pion/stun v0.6.1 + github.com/pion/webrtc/v3 v3.2.40 + github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_model v0.6.1 + github.com/quic-go/quic-go v0.44.0 + github.com/quic-go/webtransport-go v0.8.0 github.com/raulk/go-watchdog v1.3.0 - github.com/stretchr/testify v1.8.4 - go.uber.org/fx v1.20.0 - go.uber.org/goleak v1.1.12 - golang.org/x/crypto v0.11.0 - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 - golang.org/x/sync v0.3.0 - golang.org/x/sys v0.10.0 - golang.org/x/tools v0.11.0 - google.golang.org/protobuf v1.30.0 + github.com/stretchr/testify v1.9.0 + go.uber.org/fx v1.21.1 + go.uber.org/goleak v1.3.0 + go.uber.org/mock v0.4.0 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.20.0 + golang.org/x/tools v0.21.0 + google.golang.org/protobuf v1.34.1 ) require ( @@ -66,7 +71,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.3.3 github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -76,44 +80,55 @@ require ( github.com/dustin/go-humanize v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/nxadm/tail v1.4.11 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.3 // indirect - github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect + go.uber.org/dig v1.17.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/text v0.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/text v0.15.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) + +// Remove this once fx releases the next version. +// We want to ship with a fix around SIGINT handling: +// https://github.com/uber-go/fx/pull/1198. +// Context: https://github.com/libp2p/go-libp2p/issues/2785 +replace go.uber.org/fx v1.21.1 => github.com/uber-go/fx v1.21.2-0.20240515133256-cb9cccf55845 diff --git a/go-libp2p/go.sum b/go-libp2p/go.sum index 21ddf91..5455f12 100644 --- a/go-libp2p/go.sum +++ b/go-libp2p/go.sum @@ -2,38 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= @@ -41,14 +10,8 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -56,26 +19,16 @@ github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -95,8 +48,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= @@ -111,36 +65,19 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -152,90 +89,50 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= -github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= @@ -260,55 +157,43 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-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= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= -github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= -github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +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/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= @@ -319,16 +204,14 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -341,11 +224,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -355,8 +235,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= -github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -368,83 +248,103 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +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/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= -github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= -github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.36.3 h1:f+yOqeGhMoRX7/M3wmEw/djhzKWr15FtQysox85/834= -github.com/quic-go/quic-go v0.36.3/go.mod h1:qxQumdeKw5GmWs1OsTZZnOxzSI+RJWuhf1O8FN35L2o= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -471,9 +371,6 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go. github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= @@ -487,45 +384,44 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +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.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/uber-go/fx v1.21.2-0.20240515133256-cb9cccf55845 h1:1ZbnuG7aj1UxZnfsJmEpACmspZMkj5Fdvg7C1yWgQCE= +github.com/uber-go/fx v1.21.2-0.20240515133256-cb9cccf55845/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= -go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -533,113 +429,78 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/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.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -647,90 +508,74 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.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.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -738,51 +583,18 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -790,93 +602,23 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -889,11 +631,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -902,15 +640,8 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/go-libp2p/leaky_tests/README.md b/go-libp2p/leaky_tests/README.md new file mode 100644 index 0000000..398a91a --- /dev/null +++ b/go-libp2p/leaky_tests/README.md @@ -0,0 +1 @@ +Tests that leak goroutines for various reasons. Mostly because libp2p node shutdown logic doesn't run if we fail to construct the node. diff --git a/go-libp2p/leaky_tests/leaky_test.go b/go-libp2p/leaky_tests/leaky_test.go new file mode 100644 index 0000000..172b656 --- /dev/null +++ b/go-libp2p/leaky_tests/leaky_test.go @@ -0,0 +1,19 @@ +package leaky_test + +import ( + "strings" + "testing" + + "github.com/libp2p/go-libp2p" +) + +func TestBadTransportConstructor(t *testing.T) { + h, err := libp2p.New(libp2p.Transport(func() {})) + if err == nil { + h.Close() + t.Fatal("expected an error") + } + if !strings.Contains(err.Error(), "_test.go") { + t.Error("expected error to contain debugging info") + } +} diff --git a/go-libp2p/libp2p.go b/go-libp2p/libp2p.go index db23253..1440648 100644 --- a/go-libp2p/libp2p.go +++ b/go-libp2p/libp2p.go @@ -42,13 +42,13 @@ func ChainOptions(opts ...Option) Option { // - If no security transport is provided, the host uses the go-libp2p's noise // and/or tls encrypted transport to encrypt all traffic; // -// - If no peer identity is provided, it generates a random RSA 2048 key-pair +// - If no peer identity is provided, it generates a random Ed25519 key-pair // and derives a new identity from it; // // - If no peerstore is provided, the host is initialized with an empty // peerstore. // -// To stop/shutdown the returned libp2p node, the user needs to cancel the passed context and call `Close` on the returned Host. +// To stop/shutdown the returned libp2p node, the user needs to call `Close` on the returned Host. func New(opts ...Option) (host.Host, error) { return NewWithoutDefaults(append(opts, FallbackDefaults)...) } diff --git a/go-libp2p/libp2p_test.go b/go-libp2p/libp2p_test.go index 7d947af..8a9a8ed 100644 --- a/go-libp2p/libp2p_test.go +++ b/go-libp2p/libp2p_test.go @@ -2,22 +2,31 @@ package libp2p import ( "context" + "crypto/rand" + "errors" "fmt" "regexp" - "strings" "testing" + "time" "github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/core/routing" "github.com/libp2p/go-libp2p/core/transport" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/libp2p/go-libp2p/p2p/net/swarm" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" "github.com/libp2p/go-libp2p/p2p/security/noise" tls "github.com/libp2p/go-libp2p/p2p/security/tls" quic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/tcp" webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" + "go.uber.org/goleak" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" @@ -31,17 +40,6 @@ func TestNewHost(t *testing.T) { h.Close() } -func TestBadTransportConstructor(t *testing.T) { - h, err := New(Transport(func() {})) - if err == nil { - h.Close() - t.Fatal("expected an error") - } - if !strings.Contains(err.Error(), "libp2p_test.go") { - t.Error("expected error to contain debugging info") - } -} - func TestTransportConstructor(t *testing.T) { ctor := func( h host.Host, @@ -91,15 +89,9 @@ func TestInsecure(t *testing.T) { h.Close() } -func TestAutoNATService(t *testing.T) { - h, err := New(EnableNATService()) - require.NoError(t, err) - h.Close() -} - func TestDefaultListenAddrs(t *testing.T) { reTCP := regexp.MustCompile("/(ip)[4|6]/((0.0.0.0)|(::))/tcp/") - reQUIC := regexp.MustCompile("/(ip)[4|6]/((0.0.0.0)|(::))/udp/([0-9]*)/quic") + reQUIC := regexp.MustCompile("/(ip)[4|6]/((0.0.0.0)|(::))/udp/([0-9]*)/quic-v1") reCircuit := regexp.MustCompile("/p2p-circuit") // Test 1: Setting the correct listen addresses if userDefined.Transport == nil && userDefined.ListenAddrs == nil @@ -180,7 +172,7 @@ func TestTransportConstructorTCP(t *testing.T) { require.NoError(t, err) defer h.Close() require.NoError(t, h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0"))) - err = h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")) + err = h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")) require.Error(t, err) require.Contains(t, err.Error(), swarm.ErrNoTransport.Error()) } @@ -192,7 +184,7 @@ func TestTransportConstructorQUIC(t *testing.T) { ) require.NoError(t, err) defer h.Close() - require.NoError(t, h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic"))) + require.NoError(t, h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"))) err = h.Network().Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) require.Error(t, err) require.Contains(t, err.Error(), swarm.ErrNoTransport.Error()) @@ -325,8 +317,8 @@ func TestTransportCustomAddressWebTransport(t *testing.T) { require.NotEqual(t, addrs[0], customAddr) restOfAddr, lastComp := ma.SplitLast(addrs[0]) restOfAddr, secondToLastComp := ma.SplitLast(restOfAddr) - require.Equal(t, lastComp.Protocol().Code, ma.P_CERTHASH) - require.Equal(t, secondToLastComp.Protocol().Code, ma.P_CERTHASH) + require.Equal(t, ma.P_CERTHASH, lastComp.Protocol().Code) + require.Equal(t, ma.P_CERTHASH, secondToLastComp.Protocol().Code) require.True(t, restOfAddr.Equal(customAddr)) } @@ -352,7 +344,118 @@ func TestTransportCustomAddressWebTransportDoesNotStall(t *testing.T) { addrs := h.Addrs() require.Len(t, addrs, 1) _, lastComp := ma.SplitLast(addrs[0]) - require.NotEqual(t, lastComp.Protocol().Code, ma.P_CERTHASH) + require.NotEqual(t, ma.P_CERTHASH, lastComp.Protocol().Code) // We did not add the certhash to the multiaddr require.Equal(t, addrs[0], customAddr) } + +type mockPeerRouting struct { + queried []peer.ID +} + +func (r *mockPeerRouting) FindPeer(_ context.Context, id peer.ID) (peer.AddrInfo, error) { + r.queried = append(r.queried, id) + return peer.AddrInfo{}, errors.New("mock peer routing error") +} + +func TestRoutedHost(t *testing.T) { + mockRouter := &mockPeerRouting{} + h, err := New( + NoListenAddrs, + Routing(func(host.Host) (routing.PeerRouting, error) { return mockRouter, nil }), + DisableRelay(), + ) + require.NoError(t, err) + defer h.Close() + + priv, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + id, err := peer.IDFromPrivateKey(priv) + require.NoError(t, err) + require.EqualError(t, h.Connect(context.Background(), peer.AddrInfo{ID: id}), "mock peer routing error") + require.Equal(t, []peer.ID{id}, mockRouter.queried) +} + +func TestAutoNATService(t *testing.T) { + h, err := New(EnableNATService()) + require.NoError(t, err) + h.Close() +} + +func TestInsecureConstructor(t *testing.T) { + h, err := New( + EnableNATService(), + NoSecurity, + ) + require.NoError(t, err) + h.Close() + + h, err = New( + NoSecurity, + ) + require.NoError(t, err) + h.Close() +} + +func TestDisableIdentifyAddressDiscovery(t *testing.T) { + h, err := New(DisableIdentifyAddressDiscovery()) + require.NoError(t, err) + h.Close() +} + +func TestMain(m *testing.M) { + goleak.VerifyTestMain( + m, + // This will return eventually (5s timeout) but doesn't take a context. + goleak.IgnoreAnyFunction("github.com/koron/go-ssdp.Search"), + // Logging & Stats + goleak.IgnoreTopFunction("github.com/ipfs/go-log/v2/writer.(*MirrorWriter).logRoutine"), + goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), + goleak.IgnoreAnyFunction("github.com/jackpal/go-nat-pmp.(*Client).GetExternalAddress"), + ) +} + +func TestDialCircuitAddrWithWrappedResourceManager(t *testing.T) { + relay, err := New(EnableRelayService()) + require.NoError(t, err) + defer relay.Close() + + // Fake that the relay is publicly reachable + emitterForRelay, err := relay.EventBus().Emitter(&event.EvtLocalReachabilityChanged{}) + require.NoError(t, err) + defer emitterForRelay.Close() + emitterForRelay.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPublic}) + + peerBehindRelay, err := New(EnableAutoRelayWithStaticRelays([]peer.AddrInfo{{ID: relay.ID(), Addrs: relay.Addrs()}})) + require.NoError(t, err) + defer peerBehindRelay.Close() + // Emit an event to tell this peer it is private + emitterForPeerBehindRelay, err := peerBehindRelay.EventBus().Emitter(&event.EvtLocalReachabilityChanged{}) + require.NoError(t, err) + defer emitterForPeerBehindRelay.Close() + emitterForPeerBehindRelay.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate}) + + // Use a wrapped resource manager to test that the circuit dialing works + // with it. Look at the PR introducing this test for context + type wrappedRcmgr struct{ network.ResourceManager } + mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale())) + require.NoError(t, err) + wmgr := wrappedRcmgr{mgr} + h, err := New(ResourceManager(wmgr)) + require.NoError(t, err) + defer h.Close() + + h.Peerstore().AddAddrs(relay.ID(), relay.Addrs(), 10*time.Minute) + h.Peerstore().AddAddr(peerBehindRelay.ID(), + ma.StringCast( + fmt.Sprintf("/p2p/%s/p2p-circuit", relay.ID()), + ), + peerstore.TempAddrTTL, + ) + require.NoError(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + res := <-ping.Ping(ctx, h, peerBehindRelay.ID()) + require.NoError(t, res.Error) + defer cancel() +} diff --git a/go-libp2p/options.go b/go-libp2p/options.go index beb4930..de95251 100644 --- a/go-libp2p/options.go +++ b/go-libp2p/options.go @@ -349,7 +349,7 @@ func EnableAutoRelayWithPeerSource(peerSource autorelay.PeerSource, opts ...auto // forcing the local node to believe it is reachable externally. func ForceReachabilityPublic() Option { return func(cfg *Config) error { - public := network.Reachability(network.ReachabilityPublic) + public := network.ReachabilityPublic cfg.AutoNATConfig.ForceReachability = &public return nil } @@ -359,7 +359,7 @@ func ForceReachabilityPublic() Option { // forceing the local node to believe it is behind a NAT and not reachable externally. func ForceReachabilityPrivate() Option { return func(cfg *Config) error { - private := network.Reachability(network.ReachabilityPrivate) + private := network.ReachabilityPrivate cfg.AutoNATConfig.ForceReachability = &private return nil } @@ -579,6 +579,7 @@ func PrometheusRegisterer(reg prometheus.Registerer) Option { // DialRanker configures libp2p to use d as the dial ranker. To enable smart // dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to // disable smart dialing. +// // Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead func DialRanker(d network.DialRanker) Option { return func(cfg *Config) error { @@ -597,3 +598,14 @@ func SwarmOpts(opts ...swarm.Option) Option { return nil } } + +// DisableIdentifyAddressDiscovery disables address discovery using peer provided observed addresses +// in identify. If you know your public addresses upfront, the recommended way is to use +// AddressFactory to provide the external adddress to the host and use this option to disable +// discovery from identify. +func DisableIdentifyAddressDiscovery() Option { + return func(cfg *Config) error { + cfg.DisableIdentifyAddressDiscovery = true + return nil + } +} diff --git a/go-libp2p/p2p/discovery/backoff/backoffcache.go b/go-libp2p/p2p/discovery/backoff/backoffcache.go index 82c0724..c8f1180 100644 --- a/go-libp2p/p2p/discovery/backoff/backoffcache.go +++ b/go-libp2p/p2p/discovery/backoff/backoffcache.go @@ -82,14 +82,6 @@ func (c realClock) Now() time.Time { return time.Now() } -// withClock lets you override the default time.Now() call. Useful for tests. -func withClock(c clock) BackoffDiscoveryOption { - return func(b *BackoffDiscovery) error { - b.clock = c - return nil - } -} - type backoffCache struct { // strat is assigned on creation and not written to strat BackoffStrategy diff --git a/go-libp2p/p2p/discovery/backoff/backoffcache_test.go b/go-libp2p/p2p/discovery/backoff/backoffcache_test.go index fe528cc..6679415 100644 --- a/go-libp2p/p2p/discovery/backoff/backoffcache_test.go +++ b/go-libp2p/p2p/discovery/backoff/backoffcache_test.go @@ -80,6 +80,14 @@ func assertNumPeersWithLimit(t *testing.T, ctx context.Context, d discovery.Disc } } +// withClock lets you override the default time.Now() call. Useful for tests. +func withClock(c clock) BackoffDiscoveryOption { + return func(b *BackoffDiscovery) error { + b.clock = c + return nil + } +} + func TestBackoffDiscoverySingleBackoff(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/go-libp2p/p2p/host/autonat/autonat.go b/go-libp2p/p2p/host/autonat/autonat.go index fc8c676..479f31e 100644 --- a/go-libp2p/p2p/host/autonat/autonat.go +++ b/go-libp2p/p2p/host/autonat/autonat.go @@ -431,7 +431,7 @@ func (as *AmbientAutoNAT) getPeerToProbe() peer.ID { func (as *AmbientAutoNAT) Close() error { as.ctxCancel() if as.service != nil { - as.service.Disable() + return as.service.Close() } <-as.backgroundRunning return nil @@ -444,7 +444,7 @@ func (s *StaticAutoNAT) Status() network.Reachability { func (s *StaticAutoNAT) Close() error { if s.service != nil { - s.service.Disable() + return s.service.Close() } return nil } diff --git a/go-libp2p/p2p/host/autonat/svc.go b/go-libp2p/p2p/host/autonat/svc.go index 98b421c..d293550 100644 --- a/go-libp2p/p2p/host/autonat/svc.go +++ b/go-libp2p/p2p/host/autonat/svc.go @@ -68,7 +68,7 @@ func (as *autoNATService) handleStream(s network.Stream) { defer s.Close() pid := s.Conn().RemotePeer() - log.Debugf("New stream from %s", pid.Pretty()) + log.Debugf("New stream from %s", pid) r := pbio.NewDelimitedReader(s, maxMsgSize) w := pbio.NewDelimitedWriter(s) @@ -78,14 +78,14 @@ func (as *autoNATService) handleStream(s network.Stream) { err := r.ReadMsg(&req) if err != nil { - log.Debugf("Error reading message from %s: %s", pid.Pretty(), err.Error()) + log.Debugf("Error reading message from %s: %s", pid, err.Error()) s.Reset() return } t := req.GetType() if t != pb.Message_DIAL { - log.Debugf("Unexpected message from %s: %s (%d)", pid.Pretty(), t.String(), t) + log.Debugf("Unexpected message from %s: %s (%d)", pid, t.String(), t) s.Reset() return } @@ -96,7 +96,7 @@ func (as *autoNATService) handleStream(s network.Stream) { err = w.WriteMsg(&res) if err != nil { - log.Debugf("Error writing response to %s: %s", pid.Pretty(), err.Error()) + log.Debugf("Error writing response to %s: %s", pid, err.Error()) s.Reset() return } @@ -234,7 +234,7 @@ func (as *autoNATService) doDial(pi peer.AddrInfo) *pb.Message_DialResponse { conn, err := as.config.dialer.DialPeer(ctx, pi.ID) if err != nil { - log.Debugf("error dialing %s: %s", pi.ID.Pretty(), err.Error()) + log.Debugf("error dialing %s: %s", pi.ID, err.Error()) // wait for the context to timeout to avoid leaking timing information // this renders the service ineffective as a port scanner <-ctx.Done() @@ -273,6 +273,11 @@ func (as *autoNATService) Disable() { } } +func (as *autoNATService) Close() error { + as.Disable() + return as.config.dialer.Close() +} + func (as *autoNATService) background(ctx context.Context) { defer close(as.backgroundRunning) diff --git a/go-libp2p/p2p/host/autonat/svc_test.go b/go-libp2p/p2p/host/autonat/svc_test.go index 61e6038..d58a9b7 100644 --- a/go-libp2p/p2p/host/autonat/svc_test.go +++ b/go-libp2p/p2p/host/autonat/svc_test.go @@ -189,7 +189,7 @@ func TestAutoNATServiceRateLimitJitter(t *testing.T) { svc.mx.Lock() defer svc.mx.Unlock() return svc.globalReqs == 0 - }, dur*5/2, 10*time.Millisecond, "reset of rate limitter occured slower than expected") + }, dur*5/2, 10*time.Millisecond, "reset of rate limiter occurred slower than expected") } func TestAutoNATServiceStartup(t *testing.T) { diff --git a/go-libp2p/p2p/host/autorelay/addrsplosion.go b/go-libp2p/p2p/host/autorelay/addrsplosion.go index c6353b1..710dab1 100644 --- a/go-libp2p/p2p/host/autorelay/addrsplosion.go +++ b/go-libp2p/p2p/host/autorelay/addrsplosion.go @@ -54,7 +54,7 @@ func isRelayAddr(a ma.Multiaddr) bool { func isDNSAddr(a ma.Multiaddr) bool { if first, _ := ma.SplitFirst(a); first != nil { switch first.Protocol().Code { - case ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: + case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: return true } } diff --git a/go-libp2p/p2p/host/autorelay/addrsplosion_test.go b/go-libp2p/p2p/host/autorelay/addrsplosion_test.go index 0d8a57d..1bbd910 100644 --- a/go-libp2p/p2p/host/autorelay/addrsplosion_test.go +++ b/go-libp2p/p2p/host/autorelay/addrsplosion_test.go @@ -11,14 +11,14 @@ func TestCleanupAddrs(t *testing.T) { t.Run("with no addrplosion", func(t *testing.T) { addrs := makeAddrList( "/ip4/127.0.0.1/tcp/4001", - "/ip4/127.0.0.1/udp/4002/quic", + "/ip4/127.0.0.1/udp/4002/quic-v1", "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", "/dnsaddr/somedomain.com/tcp/4002/ws", ) clean := makeAddrList( "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", "/dnsaddr/somedomain.com/tcp/4002/ws", ) require.ElementsMatch(t, clean, cleanupAddressSet(addrs), "cleaned up set doesn't match expected") @@ -32,11 +32,11 @@ func TestCleanupAddrs(t *testing.T) { "/ip4/1.2.3.4/tcp/33333", "/ip4/1.2.3.4/tcp/33334", "/ip4/1.2.3.4/tcp/33335", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", ) clean := makeAddrList( "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", ) require.ElementsMatch(t, clean, cleanupAddressSet(addrs), "cleaned up set doesn't match expected") }) @@ -48,11 +48,11 @@ func TestCleanupAddrs(t *testing.T) { "/ip4/1.2.3.4/tcp/33333", "/ip4/1.2.3.4/tcp/33334", "/ip4/1.2.3.4/tcp/33335", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", ) clean := makeAddrList( "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic", + "/ip4/1.2.3.4/udp/4002/quic-v1", ) require.ElementsMatch(t, clean, cleanupAddressSet(addrs), "cleaned up set doesn't match expected") }) @@ -75,7 +75,7 @@ func TestCleanupAddrs(t *testing.T) { // test with a squeaky clean address set addrs := makeAddrList( "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4001/quic", + "/ip4/1.2.3.4/udp/4001/quic-v1", ) require.ElementsMatch(t, addrs, cleanupAddressSet(addrs), "cleaned up set doesn't match expected") }) diff --git a/go-libp2p/p2p/host/autorelay/host.go b/go-libp2p/p2p/host/autorelay/host.go deleted file mode 100644 index c6bd9c5..0000000 --- a/go-libp2p/p2p/host/autorelay/host.go +++ /dev/null @@ -1,23 +0,0 @@ -package autorelay - -import ( - "github.com/libp2p/go-libp2p/core/host" -) - -type AutoRelayHost struct { - host.Host - ar *AutoRelay -} - -func (h *AutoRelayHost) Close() error { - _ = h.ar.Close() - return h.Host.Close() -} - -func (h *AutoRelayHost) Start() { - h.ar.Start() -} - -func NewAutoRelayHost(h host.Host, ar *AutoRelay) *AutoRelayHost { - return &AutoRelayHost{Host: h, ar: ar} -} diff --git a/go-libp2p/p2p/host/autorelay/metrics.go b/go-libp2p/p2p/host/autorelay/metrics.go index 8028655..af4b53e 100644 --- a/go-libp2p/p2p/host/autorelay/metrics.go +++ b/go-libp2p/p2p/host/autorelay/metrics.go @@ -59,7 +59,7 @@ var ( prometheus.CounterOpts{ Namespace: metricNamespace, Name: "candidates_circuit_v2_support_total", - Help: "Candidiates supporting circuit v2", + Help: "Candidates supporting circuit v2", }, []string{"support"}, ) @@ -167,7 +167,7 @@ func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer { metricshelper.RegisterCollectors(setting.reg, collectors...) // Initialise these counters to 0 otherwise the first reservation requests aren't handled - // correctly when using promql increse function + // correctly when using promql increase function reservationRequestsOutcomeTotal.WithLabelValues("refresh", "success") reservationRequestsOutcomeTotal.WithLabelValues("new", "success") candidatesCircuitV2SupportTotal.WithLabelValues("yes") diff --git a/go-libp2p/p2p/host/autorelay/relay_finder.go b/go-libp2p/p2p/host/autorelay/relay_finder.go index 3133b7a..13f8c63 100644 --- a/go-libp2p/p2p/host/autorelay/relay_finder.go +++ b/go-libp2p/p2p/host/autorelay/relay_finder.go @@ -63,7 +63,7 @@ type relayFinder struct { candidates map[peer.ID]*candidate backoff map[peer.ID]time.Time maybeConnectToRelayTrigger chan struct{} // cap: 1 - // Any time _something_ hapens that might cause us to need new candidates. + // Any time _something_ happens that might cause us to need new candidates. // This could be // * the disconnection of a relay // * the failed attempt to obtain a reservation with a current candidate @@ -736,7 +736,7 @@ func (rf *relayFinder) relayAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { for p := range rf.relays { addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p)) relayAddrCnt += len(addrs) - circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p.Pretty())) + circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p)) for _, addr := range addrs { pub := addr.Encapsulate(circuit) raddrs = append(raddrs, pub) diff --git a/go-libp2p/p2p/host/basic/basic_host.go b/go-libp2p/p2p/host/basic/basic_host.go index 79f02e2..8fc808e 100644 --- a/go-libp2p/p2p/host/basic/basic_host.go +++ b/go-libp2p/p2p/host/basic/basic_host.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net" + "slices" "sync" "time" @@ -27,6 +28,7 @@ import ( "github.com/libp2p/go-libp2p/p2p/protocol/holepunch" "github.com/libp2p/go-libp2p/p2p/protocol/identify" "github.com/libp2p/go-libp2p/p2p/protocol/ping" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" "github.com/prometheus/client_golang/prometheus" @@ -52,6 +54,8 @@ var ( DefaultAddrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr { return addrs } ) +const maxPeerRecordSize = 8 * 1024 // 8k to be compatible with identify's limit + // AddrsFactory functions can be passed to New in order to override // addresses returned by Addrs. type AddrsFactory func([]ma.Multiaddr) []ma.Multiaddr @@ -160,6 +164,9 @@ type HostOpts struct { EnableMetrics bool // PrometheusRegisterer is the PrometheusRegisterer used for metrics PrometheusRegisterer prometheus.Registerer + + // DisableIdentifyAddressDiscovery disables address discovery using peer provided observed addresses in identify + DisableIdentifyAddressDiscovery bool } // NewHost constructs a new *BasicHost and activates it by attaching its stream and connection handlers to the given inet.Network. @@ -171,12 +178,11 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) { opts.EventBus = eventbus.NewBus() } - psManager, err := pstoremanager.NewPeerstoreManager(n.Peerstore(), opts.EventBus) + psManager, err := pstoremanager.NewPeerstoreManager(n.Peerstore(), opts.EventBus, n) if err != nil { return nil, err } hostCtx, cancel := context.WithCancel(context.Background()) - h := &BasicHost{ network: n, psManager: psManager, @@ -244,6 +250,9 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) { identify.WithMetricsTracer( identify.NewMetricsTracer(identify.WithRegisterer(opts.PrometheusRegisterer)))) } + if opts.DisableIdentifyAddressDiscovery { + idOpts = append(idOpts, identify.DisableObservedAddrManager()) + } h.ids, err = identify.NewIDService(h, idOpts...) if err != nil { @@ -415,7 +424,7 @@ func (h *BasicHost) newStreamHandler(s network.Stream) { } logf("protocol EOF: %s (took %s)", s.Conn().RemotePeer(), took) } else { - log.Debugf("protocol mux failed: %s (took %s)", err, took) + log.Debugf("protocol mux failed: %s (took %s, id:%s, remote peer:%s, remote addr:%v)", err, took, s.ID(), s.Conn().RemotePeer(), s.Conn().RemoteMultiaddr()) } s.Reset() return @@ -437,7 +446,7 @@ func (h *BasicHost) newStreamHandler(s network.Stream) { log.Debugf("negotiated: %s (took %s)", protoID, took) - go handle(protoID, s) + handle(protoID, s) } // SignalAddressChange signals to the host that it needs to determine whether our listen addresses have recently @@ -482,15 +491,18 @@ func makeUpdatedAddrEvent(prev, current []ma.Multiaddr) *event.EvtLocalAddresses return &evt } -func (h *BasicHost) makeSignedPeerRecord(evt *event.EvtLocalAddressesUpdated) (*record.Envelope, error) { - current := make([]ma.Multiaddr, 0, len(evt.Current)) - for _, a := range evt.Current { - current = append(current, a.Address) +func (h *BasicHost) makeSignedPeerRecord(addrs []ma.Multiaddr) (*record.Envelope, error) { + // Limit the length of currentAddrs to ensure that our signed peer records aren't rejected + peerRecordSize := 64 // HostID + k, err := h.signKey.Raw() + if err != nil { + peerRecordSize += 2 * len(k) // 1 for signature, 1 for public key } - + // we want the final address list to be small for keeping the signed peer record in size + addrs = trimHostAddrList(addrs, maxPeerRecordSize-peerRecordSize-256) // 256 B of buffer rec := peer.PeerRecordFromAddrInfo(peer.AddrInfo{ ID: h.ID(), - Addrs: current, + Addrs: addrs, }) return record.Seal(rec, h.signKey) } @@ -513,7 +525,7 @@ func (h *BasicHost) background() { if !h.disableSignedPeerRecord { // add signed peer record to the event - sr, err := h.makeSignedPeerRecord(changeEvt) + sr, err := h.makeSignedPeerRecord(currentAddrs) if err != nil { log.Errorf("error creating a signed peer record from the set of current addresses, err=%s", err) return @@ -543,7 +555,7 @@ func (h *BasicHost) background() { h.updateLocalIpAddr() } // Request addresses anyways because, technically, address filters still apply. - // The underlying AllAddrs call is effectivley a no-op. + // The underlying AllAddrs call is effectively a no-op. curr := h.Addrs() emitAddrChange(curr, lastAddrs) lastAddrs = curr @@ -666,7 +678,9 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I } if pref != "" { - s.SetProtocol(pref) + if err := s.SetProtocol(pref); err != nil { + return nil, err + } lzcon := msmux.NewMSSelect(s, pref) return &streamWrapper{ Stream: s, @@ -722,8 +736,10 @@ func (h *BasicHost) Connect(ctx context.Context, pi peer.AddrInfo) error { h.Peerstore().AddAddrs(pi.ID, pi.Addrs, peerstore.TempAddrTTL) forceDirect, _ := network.GetForceDirectDial(ctx) + canUseLimitedConn, _ := network.GetAllowLimitedConn(ctx) if !forceDirect { - if h.Network().Connectedness(pi.ID) == network.Connected { + connectedness := h.Network().Connectedness(pi.ID) + if connectedness == network.Connected || (canUseLimitedConn && connectedness == network.Limited) { return nil } } @@ -785,26 +801,34 @@ func (h *BasicHost) Addrs() []ma.Multiaddr { copy(addrs, addrsOld) for i, addr := range addrs { - if ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr); ok && n == 0 { + wtOK, wtN := libp2pwebtransport.IsWebtransportMultiaddr(addr) + webrtcOK, webrtcN := libp2pwebrtc.IsWebRTCDirectMultiaddr(addr) + if (wtOK && wtN == 0) || (webrtcOK && webrtcN == 0) { t := s.TransportForListening(addr) tpt, ok := t.(addCertHasher) if !ok { continue } addrWithCerthash, added := tpt.AddCertHashes(addr) - addrs[i] = addrWithCerthash if !added { - log.Debug("Couldn't add certhashes to webtransport multiaddr because we aren't listening on webtransport") + log.Debugf("Couldn't add certhashes to multiaddr: %s", addr) + continue } + addrs[i] = addrWithCerthash } } + return addrs } // NormalizeMultiaddr returns a multiaddr suitable for equality checks. // If the multiaddr is a webtransport component, it removes the certhashes. func (h *BasicHost) NormalizeMultiaddr(addr ma.Multiaddr) ma.Multiaddr { - if ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr); ok && n > 0 { + ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr) + if !ok { + ok, n = libp2pwebrtc.IsWebRTCDirectMultiaddr(addr) + } + if ok && n > 0 { out := addr for i := 0; i < n; i++ { out, _ = ma.SplitLast(out) @@ -942,17 +966,17 @@ func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr { // Remove certhashes addr, _ = ma.SplitLast(addr) } - webtransportAddrs[addr.String()] = struct{}{} + webtransportAddrs[string(addr.Bytes())] = struct{}{} // Remove webtransport component, now it's a multiaddr that ends in /quic-v1 addr, _ = ma.SplitLast(addr) } if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 { - addrStr := addr.String() - if _, ok := quicOrWebtransportAddrs[addrStr]; ok { + bytes := addr.Bytes() + if _, ok := quicOrWebtransportAddrs[string(bytes)]; ok { foundSameListeningAddr = true } else { - quicOrWebtransportAddrs[addrStr] = struct{}{} + quicOrWebtransportAddrs[string(bytes)] = struct{}{} } } } @@ -974,7 +998,7 @@ func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr { if _, lastComponent := ma.SplitLast(addr); lastComponent.Protocol().Code == ma.P_QUIC_V1 { // Convert quic to webtransport addr = addr.Encapsulate(wtComponent) - if _, ok := webtransportAddrs[addr.String()]; ok { + if _, ok := webtransportAddrs[string(addr.Bytes())]; ok { // We already have this address continue } @@ -986,6 +1010,58 @@ func inferWebtransportAddrsFromQuic(in []ma.Multiaddr) []ma.Multiaddr { return out } +func trimHostAddrList(addrs []ma.Multiaddr, maxSize int) []ma.Multiaddr { + totalSize := 0 + for _, a := range addrs { + totalSize += len(a.Bytes()) + } + if totalSize <= maxSize { + return addrs + } + + score := func(addr ma.Multiaddr) int { + var res int + if manet.IsPublicAddr(addr) { + res |= 1 << 12 + } else if !manet.IsIPLoopback(addr) { + res |= 1 << 11 + } + var protocolWeight int + ma.ForEach(addr, func(c ma.Component) bool { + switch c.Protocol().Code { + case ma.P_QUIC_V1: + protocolWeight = 5 + case ma.P_TCP: + protocolWeight = 4 + case ma.P_WSS: + protocolWeight = 3 + case ma.P_WEBTRANSPORT: + protocolWeight = 2 + case ma.P_WEBRTC_DIRECT: + protocolWeight = 1 + case ma.P_P2P: + return false + } + return true + }) + res |= 1 << protocolWeight + return res + } + + slices.SortStableFunc(addrs, func(a, b ma.Multiaddr) int { + return score(b) - score(a) // b-a for reverse order + }) + totalSize = 0 + for i, a := range addrs { + totalSize += len(a.Bytes()) + if totalSize > maxSize { + addrs = addrs[:i] + break + } + } + return addrs +} + // SetAutoNat sets the autonat service for the host. func (h *BasicHost) SetAutoNat(a autonat.AutoNAT) { h.addrMu.Lock() @@ -1027,7 +1103,6 @@ func (h *BasicHost) Close() error { _ = h.emitters.evtLocalProtocolsUpdated.Close() _ = h.emitters.evtLocalAddrsUpdated.Close() - h.Network().Close() h.psManager.Close() if h.Peerstore() != nil { diff --git a/go-libp2p/p2p/host/basic/basic_host_test.go b/go-libp2p/p2p/host/basic/basic_host_test.go index 1093da3..c4f0680 100644 --- a/go-libp2p/p2p/host/basic/basic_host_test.go +++ b/go-libp2p/p2p/host/basic/basic_host_test.go @@ -377,7 +377,7 @@ func TestHostProtoPreknowledge(t *testing.T) { // This test implicitly relies on 1 connection. If a background identify // completes after we set the stream handler below things break - require.Equal(t, 1, len(h1.Network().ConnsToPeer(h2.ID()))) + require.Len(t, h1.Network().ConnsToPeer(h2.ID()), 1) // wait for identify handshake to finish completely select { @@ -469,7 +469,7 @@ func TestNewStreamResolve(t *testing.T) { break } } - assert.NotEqual(t, dialAddr, "") + assert.NotEqual(t, "", dialAddr) // Add the DNS multiaddr to h1's peerstore. maddr, err := ma.NewMultiaddr(dialAddr) @@ -506,7 +506,7 @@ func TestProtoDowngrade(t *testing.T) { defer s.Close() result, err := io.ReadAll(s) assert.NoError(t, err) - assert.Equal(t, string(result), "bar") + assert.Equal(t, "bar", string(result)) connectedOn <- s.Protocol() }) @@ -527,7 +527,7 @@ func TestProtoDowngrade(t *testing.T) { defer s.Close() result, err := io.ReadAll(s) assert.NoError(t, err) - assert.Equal(t, string(result), "foo") + assert.Equal(t, "foo", string(result)) connectedOn <- s.Protocol() }) @@ -838,6 +838,11 @@ func TestInferWebtransportAddrsFromQuic(t *testing.T) { in: []string{"/ip4/0.0.0.0/udp/9999/quic-v1", "/ip4/0.0.0.0/udp/9999/quic-v1/webtransport", "/ip4/1.2.3.4/udp/9999/quic-v1"}, out: []string{"/ip4/0.0.0.0/udp/9999/quic-v1", "/ip4/0.0.0.0/udp/9999/quic-v1/webtransport", "/ip4/1.2.3.4/udp/9999/quic-v1", "/ip4/1.2.3.4/udp/9999/quic-v1/webtransport"}, }, + { + name: "Happy Path With CertHashes", + in: []string{"/ip4/0.0.0.0/udp/9999/quic-v1", "/ip4/0.0.0.0/udp/9999/quic-v1/webtransport/certhash/uEgNmb28/certhash/uEgNmb28", "/ip4/1.2.3.4/udp/9999/quic-v1"}, + out: []string{"/ip4/0.0.0.0/udp/9999/quic-v1", "/ip4/0.0.0.0/udp/9999/quic-v1/webtransport/certhash/uEgNmb28/certhash/uEgNmb28", "/ip4/1.2.3.4/udp/9999/quic-v1", "/ip4/1.2.3.4/udp/9999/quic-v1/webtransport"}, + }, { name: "Already discovered", in: []string{"/ip4/0.0.0.0/udp/9999/quic-v1", "/ip4/0.0.0.0/udp/9999/quic-v1/webtransport", "/ip4/1.2.3.4/udp/9999/quic-v1", "/ip4/1.2.3.4/udp/9999/quic-v1/webtransport"}, @@ -877,9 +882,6 @@ func TestInferWebtransportAddrsFromQuic(t *testing.T) { sort.StringSlice(tc.in).Sort() sort.StringSlice(tc.out).Sort() min := make([]ma.Multiaddr, 0, len(tc.in)) - sort.Slice(tc.in, func(i, j int) bool { - return tc.in[i] < tc.in[j] - }) for _, addr := range tc.in { min = append(min, ma.StringCast(addr)) } @@ -894,3 +896,55 @@ func TestInferWebtransportAddrsFromQuic(t *testing.T) { } } + +func TestTrimHostAddrList(t *testing.T) { + type testCase struct { + name string + in []ma.Multiaddr + threshold int + out []ma.Multiaddr + } + + tcpPublic := ma.StringCast("/ip4/1.1.1.1/tcp/1") + quicPublic := ma.StringCast("/ip4/1.1.1.1/udp/1/quic-v1") + + tcpPrivate := ma.StringCast("/ip4/192.168.1.1/tcp/1") + quicPrivate := ma.StringCast("/ip4/192.168.1.1/udp/1/quic-v1") + + tcpLocal := ma.StringCast("/ip4/127.0.0.1/tcp/1") + quicLocal := ma.StringCast("/ip4/127.0.0.1/udp/1/quic-v1") + + testCases := []testCase{ + { + name: "Public preferred over private", + in: []ma.Multiaddr{tcpPublic, quicPrivate}, + threshold: len(tcpLocal.Bytes()), + out: []ma.Multiaddr{tcpPublic}, + }, + { + name: "Public and private preffered over local", + in: []ma.Multiaddr{tcpPublic, tcpPrivate, quicLocal}, + threshold: len(tcpPublic.Bytes()) + len(tcpPrivate.Bytes()), + out: []ma.Multiaddr{tcpPublic, tcpPrivate}, + }, + { + name: "quic preferred over tcp", + in: []ma.Multiaddr{tcpPublic, quicPublic}, + threshold: len(quicPublic.Bytes()), + out: []ma.Multiaddr{quicPublic}, + }, + { + name: "no filtering on large threshold", + in: []ma.Multiaddr{tcpPublic, quicPublic, quicLocal, tcpLocal, tcpPrivate}, + threshold: 10000, + out: []ma.Multiaddr{tcpPublic, quicPublic, quicLocal, tcpLocal, tcpPrivate}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := trimHostAddrList(tc.in, tc.threshold) + require.ElementsMatch(t, got, tc.out) + }) + } +} diff --git a/go-libp2p/p2p/host/basic/mock_nat_test.go b/go-libp2p/p2p/host/basic/mock_nat_test.go index 4e686fa..e601e71 100644 --- a/go-libp2p/p2p/host/basic/mock_nat_test.go +++ b/go-libp2p/p2p/host/basic/mock_nat_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/p2p/host/basic (interfaces: NAT) +// +// Generated by this command: +// +// mockgen -build_flags=-tags=gomock -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT +// // Package basichost is a generated GoMock package. package basichost @@ -9,7 +14,7 @@ import ( netip "net/netip" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockNAT is a mock of NAT interface. @@ -44,7 +49,7 @@ func (m *MockNAT) AddMapping(arg0 context.Context, arg1 string, arg2 int) error } // AddMapping indicates an expected call of AddMapping. -func (mr *MockNATMockRecorder) AddMapping(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) AddMapping(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMapping", reflect.TypeOf((*MockNAT)(nil).AddMapping), arg0, arg1, arg2) } @@ -73,7 +78,7 @@ func (m *MockNAT) GetMapping(arg0 string, arg1 int) (netip.AddrPort, bool) { } // GetMapping indicates an expected call of GetMapping. -func (mr *MockNATMockRecorder) GetMapping(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) GetMapping(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMapping", reflect.TypeOf((*MockNAT)(nil).GetMapping), arg0, arg1) } @@ -87,7 +92,7 @@ func (m *MockNAT) RemoveMapping(arg0 context.Context, arg1 string, arg2 int) err } // RemoveMapping indicates an expected call of RemoveMapping. -func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMapping", reflect.TypeOf((*MockNAT)(nil).RemoveMapping), arg0, arg1, arg2) } diff --git a/go-libp2p/p2p/host/basic/mocks.go b/go-libp2p/p2p/host/basic/mocks.go index 3ad4d4e..a29a0c5 100644 --- a/go-libp2p/p2p/host/basic/mocks.go +++ b/go-libp2p/p2p/host/basic/mocks.go @@ -2,5 +2,5 @@ package basichost -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT" type NAT nat diff --git a/go-libp2p/p2p/host/basic/natmgr.go b/go-libp2p/p2p/host/basic/natmgr.go index 8e8fbea..bc55e4d 100644 --- a/go-libp2p/p2p/host/basic/natmgr.go +++ b/go-libp2p/p2p/host/basic/natmgr.go @@ -127,7 +127,7 @@ func (nmgr *natManager) background(ctx context.Context) { for { select { case <-nmgr.syncFlag: - nmgr.doSync() // sync when our listen addresses chnage. + nmgr.doSync() // sync when our listen addresses change. case <-ctx.Done(): return } diff --git a/go-libp2p/p2p/host/basic/natmgr_test.go b/go-libp2p/p2p/host/basic/natmgr_test.go index d22092d..8cbe861 100644 --- a/go-libp2p/p2p/host/basic/natmgr_test.go +++ b/go-libp2p/p2p/host/basic/natmgr_test.go @@ -12,7 +12,7 @@ import ( swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" - "github.com/golang/mock/gomock" + "go.uber.org/mock/gomock" ) func setupMockNAT(t *testing.T) (mockNAT *MockNAT, reset func()) { diff --git a/go-libp2p/p2p/host/blank/blank.go b/go-libp2p/p2p/host/blank/blank.go index 2430449..0cf6642 100644 --- a/go-libp2p/p2p/host/blank/blank.go +++ b/go-libp2p/p2p/host/blank/blank.go @@ -63,9 +63,10 @@ func NewBlankHost(n network.Network, options ...Option) *BlankHost { } bh := &BlankHost{ - n: n, - cmgr: cfg.cmgr, - mux: mstream.NewMultistreamMuxer[protocol.ID](), + n: n, + cmgr: cfg.cmgr, + mux: mstream.NewMultistreamMuxer[protocol.ID](), + eventbus: cfg.eventBus, } if bh.eventbus == nil { bh.eventbus = eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer())) @@ -210,7 +211,7 @@ func (bh *BlankHost) newStreamHandler(s network.Stream) { s.SetProtocol(protoID) - go handle(protoID, s) + handle(protoID, s) } // TODO: i'm not sure this really needs to be here diff --git a/go-libp2p/p2p/host/peerstore/pstoreds/addr_book.go b/go-libp2p/p2p/host/peerstore/pstoreds/addr_book.go index a16053b..2023de1 100644 --- a/go-libp2p/p2p/host/peerstore/pstoreds/addr_book.go +++ b/go-libp2p/p2p/host/peerstore/pstoreds/addr_book.go @@ -14,7 +14,7 @@ import ( "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoreds/pb" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" - lru "github.com/hashicorp/golang-lru/v2" + "github.com/hashicorp/golang-lru/arc/v2" ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/query" logging "github.com/ipfs/go-log/v2" @@ -202,7 +202,7 @@ func NewAddrBook(ctx context.Context, store ds.Batching, opts Options) (ab *dsAd } if opts.CacheSize > 0 { - if ab.cache, err = lru.NewARC[peer.ID, *addrsRecord](int(opts.CacheSize)); err != nil { + if ab.cache, err = arc.NewARC[peer.ID, *addrsRecord](int(opts.CacheSize)); err != nil { return nil, err } } else { @@ -362,7 +362,7 @@ func (ab *dsAddrBook) storeSignedPeerRecord(p peer.ID, envelope *record.Envelope func (ab *dsAddrBook) GetPeerRecord(p peer.ID) *record.Envelope { pr, err := ab.loadRecord(p, true, false) if err != nil { - log.Errorf("unable to load record for peer %s: %v", p.Pretty(), err) + log.Errorf("unable to load record for peer %s: %v", p, err) return nil } pr.RLock() @@ -372,7 +372,7 @@ func (ab *dsAddrBook) GetPeerRecord(p peer.ID) *record.Envelope { } state, _, err := record.ConsumeEnvelope(pr.CertifiedRecord.Raw, peer.PeerRecordEnvelopeDomain) if err != nil { - log.Errorf("error unmarshaling stored signed peer record for peer %s: %v", p.Pretty(), err) + log.Errorf("error unmarshaling stored signed peer record for peer %s: %v", p, err) return nil } return state @@ -398,7 +398,7 @@ func (ab *dsAddrBook) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duratio func (ab *dsAddrBook) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration) { pr, err := ab.loadRecord(p, true, false) if err != nil { - log.Errorf("failed to update ttls for peer %s: %s\n", p.Pretty(), err) + log.Errorf("failed to update ttls for peer %s: %s\n", p, err) return } @@ -423,7 +423,7 @@ func (ab *dsAddrBook) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.D func (ab *dsAddrBook) Addrs(p peer.ID) []ma.Multiaddr { pr, err := ab.loadRecord(p, true, true) if err != nil { - log.Warn("failed to load peerstore entry for peer %v while querying addrs, err: %v", p, err) + log.Warnf("failed to load peerstore entry for peer %s while querying addrs, err: %v", p, err) return nil } @@ -466,7 +466,7 @@ func (ab *dsAddrBook) ClearAddrs(p peer.ID) { key := addrBookBase.ChildString(b32.RawStdEncoding.EncodeToString([]byte(p))) if err := ab.ds.Delete(context.TODO(), key); err != nil { - log.Errorf("failed to clear addresses for peer %s: %v", p.Pretty(), err) + log.Errorf("failed to clear addresses for peer %s: %v", p, err) } } @@ -477,7 +477,7 @@ func (ab *dsAddrBook) setAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duratio pr, err := ab.loadRecord(p, true, false) if err != nil { - return fmt.Errorf("failed to load peerstore entry for peer %v while setting addrs, err: %v", p, err) + return fmt.Errorf("failed to load peerstore entry for peer %s while setting addrs, err: %v", p, err) } pr.Lock() diff --git a/go-libp2p/p2p/host/peerstore/pstoreds/addr_book_gc.go b/go-libp2p/p2p/host/peerstore/pstoreds/addr_book_gc.go index a509131..2e35e7a 100644 --- a/go-libp2p/p2p/host/peerstore/pstoreds/addr_book_gc.go +++ b/go-libp2p/p2p/host/peerstore/pstoreds/addr_book_gc.go @@ -215,7 +215,7 @@ func (gc *dsAddrBookGc) purgeLookahead() { cached.Lock() if cached.clean(gc.ab.clock.Now()) { if err = cached.flush(batch); err != nil { - log.Warnf("failed to flush entry modified by GC for peer: &v, err: %v", id.Pretty(), err) + log.Warnf("failed to flush entry modified by GC for peer: %s, err: %v", id, err) } } dropOrReschedule(gcKey, cached) @@ -241,7 +241,7 @@ func (gc *dsAddrBookGc) purgeLookahead() { if record.clean(gc.ab.clock.Now()) { err = record.flush(batch) if err != nil { - log.Warnf("failed to flush entry modified by GC for peer: &v, err: %v", id.Pretty(), err) + log.Warnf("failed to flush entry modified by GC for peer: %s, err: %v", id, err) } } dropOrReschedule(gcKey, record) @@ -353,7 +353,7 @@ func (gc *dsAddrBookGc) populateLookahead() { } gcKey := gcLookaheadBase.ChildString(fmt.Sprintf("%d/%s", cached.Addrs[0].Expiry, idb32)) if err = batch.Put(context.TODO(), gcKey, []byte{}); err != nil { - log.Warnf("failed while inserting GC entry for peer: %v, err: %v", id.Pretty(), err) + log.Warnf("failed while inserting GC entry for peer: %s, err: %v", id, err) } cached.RUnlock() continue @@ -363,17 +363,17 @@ func (gc *dsAddrBookGc) populateLookahead() { val, err := gc.ab.ds.Get(context.TODO(), ds.RawKey(result.Key)) if err != nil { - log.Warnf("failed which getting record from store for peer: %v, err: %v", id.Pretty(), err) + log.Warnf("failed which getting record from store for peer: %s, err: %v", id, err) continue } if err := proto.Unmarshal(val, record); err != nil { - log.Warnf("failed while unmarshalling record from store for peer: %v, err: %v", id.Pretty(), err) + log.Warnf("failed while unmarshalling record from store for peer: %s, err: %v", id, err) continue } if len(record.Addrs) > 0 && record.Addrs[0].Expiry <= until { gcKey := gcLookaheadBase.ChildString(fmt.Sprintf("%d/%s", record.Addrs[0].Expiry, idb32)) if err = batch.Put(context.TODO(), gcKey, []byte{}); err != nil { - log.Warnf("failed while inserting GC entry for peer: %v, err: %v", id.Pretty(), err) + log.Warnf("failed while inserting GC entry for peer: %s, err: %v", id, err) } } } diff --git a/go-libp2p/p2p/host/peerstore/pstoreds/deprecate.go b/go-libp2p/p2p/host/peerstore/pstoreds/deprecate.go new file mode 100644 index 0000000..b549871 --- /dev/null +++ b/go-libp2p/p2p/host/peerstore/pstoreds/deprecate.go @@ -0,0 +1,5 @@ +// Deprecated: The database-backed peerstore will be removed from go-libp2p in the future. +// Use the memory peerstore (pstoremem) instead. +// For more details see https://github.com/libp2p/go-libp2p/issues/2329 +// and https://github.com/libp2p/go-libp2p/issues/2355. +package pstoreds diff --git a/go-libp2p/p2p/host/peerstore/pstoreds/keybook.go b/go-libp2p/p2p/host/peerstore/pstoreds/keybook.go index 9db799b..63c7e30 100644 --- a/go-libp2p/p2p/host/peerstore/pstoreds/keybook.go +++ b/go-libp2p/p2p/host/peerstore/pstoreds/keybook.go @@ -38,7 +38,7 @@ func (kb *dsKeyBook) PubKey(p peer.ID) ic.PubKey { if value, err := kb.ds.Get(context.TODO(), key); err == nil { pk, err = ic.UnmarshalPublicKey(value) if err != nil { - log.Errorf("error when unmarshalling pubkey from datastore for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error when unmarshalling pubkey from datastore for peer %s: %s\n", p, err) } } else if err == ds.ErrNotFound { pk, err = p.ExtractPublicKey() @@ -47,20 +47,20 @@ func (kb *dsKeyBook) PubKey(p peer.ID) ic.PubKey { case peer.ErrNoPublicKey: return nil default: - log.Errorf("error when extracting pubkey from peer ID for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error when extracting pubkey from peer ID for peer %s: %s\n", p, err) return nil } pkb, err := ic.MarshalPublicKey(pk) if err != nil { - log.Errorf("error when turning extracted pubkey into bytes for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error when turning extracted pubkey into bytes for peer %s: %s\n", p, err) return nil } if err := kb.ds.Put(context.TODO(), key, pkb); err != nil { - log.Errorf("error when adding extracted pubkey to peerstore for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error when adding extracted pubkey to peerstore for peer %s: %s\n", p, err) return nil } } else { - log.Errorf("error when fetching pubkey from datastore for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error when fetching pubkey from datastore for peer %s: %s\n", p, err) } return pk @@ -74,11 +74,11 @@ func (kb *dsKeyBook) AddPubKey(p peer.ID, pk ic.PubKey) error { val, err := ic.MarshalPublicKey(pk) if err != nil { - log.Errorf("error while converting pubkey byte string for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error while converting pubkey byte string for peer %s: %s\n", p, err) return err } if err := kb.ds.Put(context.TODO(), peerToKey(p, pubSuffix), val); err != nil { - log.Errorf("error while updating pubkey in datastore for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error while updating pubkey in datastore for peer %s: %s\n", p, err) return err } return nil @@ -107,11 +107,11 @@ func (kb *dsKeyBook) AddPrivKey(p peer.ID, sk ic.PrivKey) error { val, err := ic.MarshalPrivateKey(sk) if err != nil { - log.Errorf("error while converting privkey byte string for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error while converting privkey byte string for peer %s: %s\n", p, err) return err } if err := kb.ds.Put(context.TODO(), peerToKey(p, privSuffix), val); err != nil { - log.Errorf("error while updating privkey in datastore for peer %s: %s\n", p.Pretty(), err) + log.Errorf("error while updating privkey in datastore for peer %s: %s\n", p, err) } return err } diff --git a/go-libp2p/p2p/host/peerstore/pstoreds/protobook.go b/go-libp2p/p2p/host/peerstore/pstoreds/protobook.go index f5d7657..40fa7d9 100644 --- a/go-libp2p/p2p/host/peerstore/pstoreds/protobook.go +++ b/go-libp2p/p2p/host/peerstore/pstoreds/protobook.go @@ -17,7 +17,7 @@ type protoSegment struct { type protoSegments [256]*protoSegment func (s *protoSegments) get(p peer.ID) *protoSegment { - return s[byte(p[len(p)-1])] + return s[p[len(p)-1]] } var errTooManyProtocols = errors.New("too many protocols") diff --git a/go-libp2p/p2p/host/peerstore/pstoremem/addr_book.go b/go-libp2p/p2p/host/peerstore/pstoremem/addr_book.go index 67f9f91..209937c 100644 --- a/go-libp2p/p2p/host/peerstore/pstoremem/addr_book.go +++ b/go-libp2p/p2p/host/peerstore/pstoremem/addr_book.go @@ -49,7 +49,7 @@ func (segments *addrSegments) get(p peer.ID) *addrSegment { if len(p) == 0 { // it's not terribly useful to use an empty peer ID, but at least we should not panic return segments[0] } - return segments[uint8(p[len(p)-1])] + return segments[p[len(p)-1]] } type clock interface { diff --git a/go-libp2p/p2p/host/peerstore/pstoremem/protobook.go b/go-libp2p/p2p/host/peerstore/pstoremem/protobook.go index 0000f97..51c4b02 100644 --- a/go-libp2p/p2p/host/peerstore/pstoremem/protobook.go +++ b/go-libp2p/p2p/host/peerstore/pstoremem/protobook.go @@ -17,7 +17,7 @@ type protoSegment struct { type protoSegments [256]*protoSegment func (s *protoSegments) get(p peer.ID) *protoSegment { - return s[byte(p[len(p)-1])] + return s[p[len(p)-1]] } var errTooManyProtocols = errors.New("too many protocols") diff --git a/go-libp2p/p2p/host/peerstore/pstoremem/sorting_test.go b/go-libp2p/p2p/host/peerstore/pstoremem/sorting_test.go index 8ea52d1..82c76ef 100644 --- a/go-libp2p/p2p/host/peerstore/pstoremem/sorting_test.go +++ b/go-libp2p/p2p/host/peerstore/pstoremem/sorting_test.go @@ -16,5 +16,5 @@ func TestAddressSorting(t *testing.T) { l := addrList{local, u1, u2l, norm} sort.Sort(l) - require.Equal(t, l, addrList{u2l, u1, local, norm}) + require.Equal(t, addrList{u2l, u1, local, norm}, l) } diff --git a/go-libp2p/p2p/host/peerstore/test/peerstore_suite.go b/go-libp2p/p2p/host/peerstore/test/peerstore_suite.go index 576b8fd..369b459 100644 --- a/go-libp2p/p2p/host/peerstore/test/peerstore_suite.go +++ b/go-libp2p/p2p/host/peerstore/test/peerstore_suite.go @@ -144,7 +144,7 @@ func testGetStreamBeforePeerAdded(ps pstore.Peerstore) func(t *testing.T) { t.Fatal("channel shouldnt be closed yet") } if a == nil { - t.Fatal("got a nil address, thats weird") + t.Fatal("got a nil address, that's weird") } count++ if received[a.String()] { @@ -195,7 +195,7 @@ func testAddrStreamDuplicates(ps pstore.Peerstore) func(t *testing.T) { var count int for a := range ach { if a == nil { - t.Fatal("got a nil address, thats weird") + t.Fatal("got a nil address, that's weird") } count++ if received[a.String()] { @@ -337,11 +337,11 @@ func testMetadata(ps pstore.Peerstore) func(t *testing.T) { for _, p := range pids { v, err := ps.Get(p, "AgentVersion") require.NoError(t, err) - require.Equal(t, v, "string") + require.Equal(t, "string", v) v, err = ps.Get(p, "bar") require.NoError(t, err) - require.Equal(t, v, 1) + require.Equal(t, 1, v) } }) @@ -359,7 +359,7 @@ func testMetadata(ps pstore.Peerstore) func(t *testing.T) { // make sure that entries for otherP were not deleted val, err := ps.Get(otherP, "AgentVersion") require.NoError(t, err) - require.Equal(t, val, "v1") + require.Equal(t, "v1", val) }) } } diff --git a/go-libp2p/p2p/host/peerstore/test/utils.go b/go-libp2p/p2p/host/peerstore/test/utils.go index 8d327f4..254b713 100644 --- a/go-libp2p/p2p/host/peerstore/test/utils.go +++ b/go-libp2p/p2p/host/peerstore/test/utils.go @@ -38,7 +38,7 @@ func RandomPeer(b *testing.B, addrCount int) *peerpair { } for i := 0; i < addrCount; i++ { - if addrs[i], err = ma.NewMultiaddr(fmt.Sprintf(aFmt, i, pid.Pretty())); err != nil { + if addrs[i], err = ma.NewMultiaddr(fmt.Sprintf(aFmt, i, pid)); err != nil { b.Fatal(err) } } diff --git a/go-libp2p/p2p/host/pstoremanager/mock_peerstore_test.go b/go-libp2p/p2p/host/pstoremanager/mock_peerstore_test.go index fb9a282..b704cb1 100644 --- a/go-libp2p/p2p/host/pstoremanager/mock_peerstore_test.go +++ b/go-libp2p/p2p/host/pstoremanager/mock_peerstore_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/peerstore (interfaces: Peerstore) +// +// Generated by this command: +// +// mockgen -package pstoremanager_test -destination mock_peerstore_test.go github.com/libp2p/go-libp2p/core/peerstore Peerstore +// // Package pstoremanager_test is a generated GoMock package. package pstoremanager_test @@ -9,11 +14,11 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" crypto "github.com/libp2p/go-libp2p/core/crypto" peer "github.com/libp2p/go-libp2p/core/peer" protocol "github.com/libp2p/go-libp2p/core/protocol" multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" ) // MockPeerstore is a mock of Peerstore interface. @@ -46,7 +51,7 @@ func (m *MockPeerstore) AddAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 tim } // AddAddr indicates an expected call of AddAddr. -func (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAddr", reflect.TypeOf((*MockPeerstore)(nil).AddAddr), arg0, arg1, arg2) } @@ -58,7 +63,7 @@ func (m *MockPeerstore) AddAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 } // AddAddrs indicates an expected call of AddAddrs. -func (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAddrs", reflect.TypeOf((*MockPeerstore)(nil).AddAddrs), arg0, arg1, arg2) } @@ -72,7 +77,7 @@ func (m *MockPeerstore) AddPrivKey(arg0 peer.ID, arg1 crypto.PrivKey) error { } // AddPrivKey indicates an expected call of AddPrivKey. -func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPrivKey", reflect.TypeOf((*MockPeerstore)(nil).AddPrivKey), arg0, arg1) } @@ -80,7 +85,7 @@ func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock. // AddProtocols mocks base method. func (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...protocol.ID) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0} + varargs := []any{arg0} for _, a := range arg1 { varargs = append(varargs, a) } @@ -90,9 +95,9 @@ func (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...protocol.ID) error { } // AddProtocols indicates an expected call of AddProtocols. -func (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) + varargs := append([]any{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddProtocols", reflect.TypeOf((*MockPeerstore)(nil).AddProtocols), varargs...) } @@ -105,7 +110,7 @@ func (m *MockPeerstore) AddPubKey(arg0 peer.ID, arg1 crypto.PubKey) error { } // AddPubKey indicates an expected call of AddPubKey. -func (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPubKey", reflect.TypeOf((*MockPeerstore)(nil).AddPubKey), arg0, arg1) } @@ -119,7 +124,7 @@ func (m *MockPeerstore) AddrStream(arg0 context.Context, arg1 peer.ID) <-chan mu } // AddrStream indicates an expected call of AddrStream. -func (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrStream", reflect.TypeOf((*MockPeerstore)(nil).AddrStream), arg0, arg1) } @@ -133,7 +138,7 @@ func (m *MockPeerstore) Addrs(arg0 peer.ID) []multiaddr.Multiaddr { } // Addrs indicates an expected call of Addrs. -func (mr *MockPeerstoreMockRecorder) Addrs(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) Addrs(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Addrs", reflect.TypeOf((*MockPeerstore)(nil).Addrs), arg0) } @@ -145,7 +150,7 @@ func (m *MockPeerstore) ClearAddrs(arg0 peer.ID) { } // ClearAddrs indicates an expected call of ClearAddrs. -func (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearAddrs", reflect.TypeOf((*MockPeerstore)(nil).ClearAddrs), arg0) } @@ -167,7 +172,7 @@ func (mr *MockPeerstoreMockRecorder) Close() *gomock.Call { // FirstSupportedProtocol mocks base method. func (m *MockPeerstore) FirstSupportedProtocol(arg0 peer.ID, arg1 ...protocol.ID) (protocol.ID, error) { m.ctrl.T.Helper() - varargs := []interface{}{arg0} + varargs := []any{arg0} for _, a := range arg1 { varargs = append(varargs, a) } @@ -178,23 +183,23 @@ func (m *MockPeerstore) FirstSupportedProtocol(arg0 peer.ID, arg1 ...protocol.ID } // FirstSupportedProtocol indicates an expected call of FirstSupportedProtocol. -func (mr *MockPeerstoreMockRecorder) FirstSupportedProtocol(arg0 interface{}, arg1 ...interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) FirstSupportedProtocol(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) + varargs := append([]any{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSupportedProtocol", reflect.TypeOf((*MockPeerstore)(nil).FirstSupportedProtocol), varargs...) } // Get mocks base method. -func (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (interface{}, error) { +func (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (any, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get", arg0, arg1) - ret0, _ := ret[0].(interface{}) + ret0, _ := ret[0].(any) ret1, _ := ret[1].(error) return ret0, ret1 } // Get indicates an expected call of Get. -func (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockPeerstore)(nil).Get), arg0, arg1) } @@ -209,7 +214,7 @@ func (m *MockPeerstore) GetProtocols(arg0 peer.ID) ([]protocol.ID, error) { } // GetProtocols indicates an expected call of GetProtocols. -func (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProtocols", reflect.TypeOf((*MockPeerstore)(nil).GetProtocols), arg0) } @@ -223,7 +228,7 @@ func (m *MockPeerstore) LatencyEWMA(arg0 peer.ID) time.Duration { } // LatencyEWMA indicates an expected call of LatencyEWMA. -func (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatencyEWMA", reflect.TypeOf((*MockPeerstore)(nil).LatencyEWMA), arg0) } @@ -237,7 +242,7 @@ func (m *MockPeerstore) PeerInfo(arg0 peer.ID) peer.AddrInfo { } // PeerInfo indicates an expected call of PeerInfo. -func (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerInfo", reflect.TypeOf((*MockPeerstore)(nil).PeerInfo), arg0) } @@ -293,7 +298,7 @@ func (m *MockPeerstore) PrivKey(arg0 peer.ID) crypto.PrivKey { } // PrivKey indicates an expected call of PrivKey. -func (mr *MockPeerstoreMockRecorder) PrivKey(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) PrivKey(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrivKey", reflect.TypeOf((*MockPeerstore)(nil).PrivKey), arg0) } @@ -307,13 +312,13 @@ func (m *MockPeerstore) PubKey(arg0 peer.ID) crypto.PubKey { } // PubKey indicates an expected call of PubKey. -func (mr *MockPeerstoreMockRecorder) PubKey(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) PubKey(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubKey", reflect.TypeOf((*MockPeerstore)(nil).PubKey), arg0) } // Put mocks base method. -func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error { +func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 any) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Put", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -321,7 +326,7 @@ func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error { } // Put indicates an expected call of Put. -func (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockPeerstore)(nil).Put), arg0, arg1, arg2) } @@ -333,7 +338,7 @@ func (m *MockPeerstore) RecordLatency(arg0 peer.ID, arg1 time.Duration) { } // RecordLatency indicates an expected call of RecordLatency. -func (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordLatency", reflect.TypeOf((*MockPeerstore)(nil).RecordLatency), arg0, arg1) } @@ -345,7 +350,7 @@ func (m *MockPeerstore) RemovePeer(arg0 peer.ID) { } // RemovePeer indicates an expected call of RemovePeer. -func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePeer", reflect.TypeOf((*MockPeerstore)(nil).RemovePeer), arg0) } @@ -353,7 +358,7 @@ func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 interface{}) *gomock.Call { // RemoveProtocols mocks base method. func (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...protocol.ID) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0} + varargs := []any{arg0} for _, a := range arg1 { varargs = append(varargs, a) } @@ -363,9 +368,9 @@ func (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...protocol.ID) error } // RemoveProtocols indicates an expected call of RemoveProtocols. -func (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) + varargs := append([]any{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveProtocols", reflect.TypeOf((*MockPeerstore)(nil).RemoveProtocols), varargs...) } @@ -376,7 +381,7 @@ func (m *MockPeerstore) SetAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 tim } // SetAddr indicates an expected call of SetAddr. -func (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAddr", reflect.TypeOf((*MockPeerstore)(nil).SetAddr), arg0, arg1, arg2) } @@ -388,7 +393,7 @@ func (m *MockPeerstore) SetAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2 } // SetAddrs indicates an expected call of SetAddrs. -func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAddrs", reflect.TypeOf((*MockPeerstore)(nil).SetAddrs), arg0, arg1, arg2) } @@ -396,7 +401,7 @@ func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gom // SetProtocols mocks base method. func (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...protocol.ID) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0} + varargs := []any{arg0} for _, a := range arg1 { varargs = append(varargs, a) } @@ -406,16 +411,16 @@ func (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...protocol.ID) error { } // SetProtocols indicates an expected call of SetProtocols. -func (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) + varargs := append([]any{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProtocols", reflect.TypeOf((*MockPeerstore)(nil).SetProtocols), varargs...) } // SupportsProtocols mocks base method. func (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...protocol.ID) ([]protocol.ID, error) { m.ctrl.T.Helper() - varargs := []interface{}{arg0} + varargs := []any{arg0} for _, a := range arg1 { varargs = append(varargs, a) } @@ -426,9 +431,9 @@ func (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...protocol.ID) ([] } // SupportsProtocols indicates an expected call of SupportsProtocols. -func (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 any, arg1 ...any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) + varargs := append([]any{arg0}, arg1...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SupportsProtocols", reflect.TypeOf((*MockPeerstore)(nil).SupportsProtocols), varargs...) } @@ -439,7 +444,7 @@ func (m *MockPeerstore) UpdateAddrs(arg0 peer.ID, arg1, arg2 time.Duration) { } // UpdateAddrs indicates an expected call of UpdateAddrs. -func (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddrs", reflect.TypeOf((*MockPeerstore)(nil).UpdateAddrs), arg0, arg1, arg2) } diff --git a/go-libp2p/p2p/host/pstoremanager/pstoremanager.go b/go-libp2p/p2p/host/pstoremanager/pstoremanager.go index d9550f4..93cc2a9 100644 --- a/go-libp2p/p2p/host/pstoremanager/pstoremanager.go +++ b/go-libp2p/p2p/host/pstoremanager/pstoremanager.go @@ -41,6 +41,7 @@ func WithCleanupInterval(t time.Duration) Option { type PeerstoreManager struct { pstore peerstore.Peerstore eventBus event.Bus + network network.Network cancel context.CancelFunc refCount sync.WaitGroup @@ -49,11 +50,12 @@ type PeerstoreManager struct { cleanupInterval time.Duration } -func NewPeerstoreManager(pstore peerstore.Peerstore, eventBus event.Bus, opts ...Option) (*PeerstoreManager, error) { +func NewPeerstoreManager(pstore peerstore.Peerstore, eventBus event.Bus, network network.Network, opts ...Option) (*PeerstoreManager, error) { m := &PeerstoreManager{ pstore: pstore, gracePeriod: time.Minute, eventBus: eventBus, + network: network, } for _, opt := range opts { if err := opt(m); err != nil { @@ -101,20 +103,28 @@ func (m *PeerstoreManager) background(ctx context.Context, sub event.Subscriptio ev := e.(event.EvtPeerConnectednessChanged) p := ev.Peer switch ev.Connectedness { - case network.NotConnected: + case network.Connected, network.Limited: + // If we reconnect to the peer before we've cleared the information, + // keep it. This is an optimization to keep the disconnected map + // small. We still need to check that a peer is actually + // disconnected before removing it from the peer store. + delete(disconnected, p) + default: if _, ok := disconnected[p]; !ok { disconnected[p] = time.Now() } - case network.Connected: - // If we reconnect to the peer before we've cleared the information, keep it. - delete(disconnected, p) } case <-ticker.C: now := time.Now() for p, disconnectTime := range disconnected { if disconnectTime.Add(m.gracePeriod).Before(now) { - m.pstore.RemovePeer(p) - delete(disconnected, p) + // Check that the peer is actually not connected at this point. + // This avoids a race condition where the Connected notification + // is processed after this time has fired. + if m.network.Connectedness(p) != network.Connected { + m.pstore.RemovePeer(p) + delete(disconnected, p) + } } } case <-ctx.Done(): diff --git a/go-libp2p/p2p/host/pstoremanager/pstoremanager_test.go b/go-libp2p/p2p/host/pstoremanager/pstoremanager_test.go index 8726740..9321031 100644 --- a/go-libp2p/p2p/host/pstoremanager/pstoremanager_test.go +++ b/go-libp2p/p2p/host/pstoremanager/pstoremanager_test.go @@ -9,12 +9,13 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/pstoremanager" + swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) -//go:generate sh -c "go run github.com/golang/mock/mockgen -package pstoremanager_test -destination mock_peerstore_test.go github.com/libp2p/go-libp2p/core/peerstore Peerstore" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package pstoremanager_test -destination mock_peerstore_test.go github.com/libp2p/go-libp2p/core/peerstore Peerstore" func TestGracePeriod(t *testing.T) { t.Parallel() @@ -23,7 +24,7 @@ func TestGracePeriod(t *testing.T) { eventBus := eventbus.NewBus() pstore := NewMockPeerstore(ctrl) const gracePeriod = 250 * time.Millisecond - man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, pstoremanager.WithGracePeriod(gracePeriod)) + man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, swarmt.GenSwarm(t), pstoremanager.WithGracePeriod(gracePeriod)) require.NoError(t, err) defer man.Close() man.Start() @@ -51,7 +52,7 @@ func TestReconnect(t *testing.T) { eventBus := eventbus.NewBus() pstore := NewMockPeerstore(ctrl) const gracePeriod = 200 * time.Millisecond - man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, pstoremanager.WithGracePeriod(gracePeriod)) + man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, swarmt.GenSwarm(t), pstoremanager.WithGracePeriod(gracePeriod)) require.NoError(t, err) defer man.Close() man.Start() @@ -77,7 +78,7 @@ func TestClose(t *testing.T) { eventBus := eventbus.NewBus() pstore := NewMockPeerstore(ctrl) const gracePeriod = time.Hour - man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, pstoremanager.WithGracePeriod(gracePeriod)) + man, err := pstoremanager.NewPeerstoreManager(pstore, eventBus, swarmt.GenSwarm(t), pstoremanager.WithGracePeriod(gracePeriod)) require.NoError(t, err) man.Start() diff --git a/go-libp2p/p2p/host/resource-manager/README.md b/go-libp2p/p2p/host/resource-manager/README.md index 9371832..68ce0aa 100644 --- a/go-libp2p/p2p/host/resource-manager/README.md +++ b/go-libp2p/p2p/host/resource-manager/README.md @@ -161,7 +161,7 @@ belong to some service in the system. Hence, this suggests that apart from global limits, we can constrain stream usage at finer granularity, at the protocol and service level. -Once again, we disinguish between inbound and outbound streams. +Once again, we distinguish between inbound and outbound streams. Inbound streams are initiated by remote peers and consume resources in response to network events; controlling inbound stream usage is again paramount for protecting the system from overload or attack. @@ -541,7 +541,7 @@ works best. ## Examples -Here we consider some concrete examples that can ellucidate the abstract +Here we consider some concrete examples that can elucidate the abstract design as described so far. ### Stream Lifetime @@ -578,7 +578,7 @@ More specifically the following constraints apply: - the peer scope, where the limits for the peer at the other end of the stream apply. - the service scope, where the limits of the specific service owning the stream apply. -- the protcol scope, where the limits of the specific protocol for the stream apply. +- the protocol scope, where the limits of the specific protocol for the stream apply. The resource transfer that happens in the `SetProtocol` and `SetService` diff --git a/go-libp2p/p2p/host/resource-manager/conn_limiter.go b/go-libp2p/p2p/host/resource-manager/conn_limiter.go new file mode 100644 index 0000000..717249e --- /dev/null +++ b/go-libp2p/p2p/host/resource-manager/conn_limiter.go @@ -0,0 +1,288 @@ +package rcmgr + +import ( + "math" + "net/netip" + "slices" + "sync" +) + +type ConnLimitPerSubnet struct { + // This defines how big the subnet is. For example, a /24 subnet has a + // PrefixLength of 24. All IPs that share the same 24 bit prefix are in the same + // subnet. Are in the same subnet, and bound to the same limit. + PrefixLength int + // The maximum number of connections allowed for each subnet. + ConnCount int +} + +type NetworkPrefixLimit struct { + // The Network prefix for which this limit applies. + Network netip.Prefix + + // The maximum number of connections allowed for this subnet. + ConnCount int +} + +// 8 for now so that it matches the number of concurrent dials we may do +// in swarm_dial.go. With future smart dialing work we should bring this +// down +var defaultMaxConcurrentConns = 8 + +var defaultIP4Limit = ConnLimitPerSubnet{ + ConnCount: defaultMaxConcurrentConns, + PrefixLength: 32, +} +var defaultIP6Limits = []ConnLimitPerSubnet{ + { + ConnCount: defaultMaxConcurrentConns, + PrefixLength: 56, + }, + { + ConnCount: 8 * defaultMaxConcurrentConns, + PrefixLength: 48, + }, +} + +var DefaultNetworkPrefixLimitV4 = sortNetworkPrefixes([]NetworkPrefixLimit{ + { + // Loopback address for v4 https://datatracker.ietf.org/doc/html/rfc6890#section-2.2.2 + Network: netip.MustParsePrefix("127.0.0.0/8"), + ConnCount: math.MaxInt, // Unlimited + }, +}) +var DefaultNetworkPrefixLimitV6 = sortNetworkPrefixes([]NetworkPrefixLimit{ + { + // Loopback address for v6 https://datatracker.ietf.org/doc/html/rfc6890#section-2.2.3 + Network: netip.MustParsePrefix("::1/128"), + ConnCount: math.MaxInt, // Unlimited + }, +}) + +// Network prefixes limits must be sorted by most specific to least specific. This lets us +// actually use the more specific limits, otherwise only the less specific ones +// would be matched. e.g. 1.2.3.0/24 must come before 1.2.0.0/16. +func sortNetworkPrefixes(limits []NetworkPrefixLimit) []NetworkPrefixLimit { + slices.SortStableFunc(limits, func(a, b NetworkPrefixLimit) int { + return b.Network.Bits() - a.Network.Bits() + }) + return limits +} + +// WithNetworkPrefixLimit sets the limits for the number of connections allowed +// for a specific Network Prefix. Use this when you want to set higher limits +// for a specific subnet than the default limit per subnet. +func WithNetworkPrefixLimit(ipv4 []NetworkPrefixLimit, ipv6 []NetworkPrefixLimit) Option { + return func(rm *resourceManager) error { + if ipv4 != nil { + rm.connLimiter.networkPrefixLimitV4 = sortNetworkPrefixes(ipv4) + } + if ipv6 != nil { + rm.connLimiter.networkPrefixLimitV6 = sortNetworkPrefixes(ipv6) + } + return nil + } +} + +// WithLimitPerSubnet sets the limits for the number of connections allowed per +// subnet. This will limit the number of connections per subnet if that subnet +// is not defined in the NetworkPrefixLimit option. Think of this as a default +// limit for any given subnet. +func WithLimitPerSubnet(ipv4 []ConnLimitPerSubnet, ipv6 []ConnLimitPerSubnet) Option { + return func(rm *resourceManager) error { + if ipv4 != nil { + rm.connLimiter.connLimitPerSubnetV4 = ipv4 + } + if ipv6 != nil { + rm.connLimiter.connLimitPerSubnetV6 = ipv6 + } + return nil + } +} + +type connLimiter struct { + mu sync.Mutex + + // Specific Network Prefix limits. If these are set, they take precedence over the + // subnet limits. + // These must be sorted by most specific to least specific. + networkPrefixLimitV4 []NetworkPrefixLimit + networkPrefixLimitV6 []NetworkPrefixLimit + connsPerNetworkPrefixV4 []int + connsPerNetworkPrefixV6 []int + + // Subnet limits. + connLimitPerSubnetV4 []ConnLimitPerSubnet + connLimitPerSubnetV6 []ConnLimitPerSubnet + ip4connsPerLimit []map[string]int + ip6connsPerLimit []map[string]int +} + +func newConnLimiter() *connLimiter { + return &connLimiter{ + networkPrefixLimitV4: DefaultNetworkPrefixLimitV4, + networkPrefixLimitV6: DefaultNetworkPrefixLimitV6, + + connLimitPerSubnetV4: []ConnLimitPerSubnet{defaultIP4Limit}, + connLimitPerSubnetV6: defaultIP6Limits, + } +} + +func (cl *connLimiter) addNetworkPrefixLimit(isIP6 bool, npLimit NetworkPrefixLimit) { + cl.mu.Lock() + defer cl.mu.Unlock() + if isIP6 { + cl.networkPrefixLimitV6 = append(cl.networkPrefixLimitV6, npLimit) + cl.networkPrefixLimitV6 = sortNetworkPrefixes(cl.networkPrefixLimitV6) + } else { + cl.networkPrefixLimitV4 = append(cl.networkPrefixLimitV4, npLimit) + cl.networkPrefixLimitV4 = sortNetworkPrefixes(cl.networkPrefixLimitV4) + } +} + +// addConn adds a connection for the given IP address. It returns true if the connection is allowed. +func (cl *connLimiter) addConn(ip netip.Addr) bool { + cl.mu.Lock() + defer cl.mu.Unlock() + networkPrefixLimits := cl.networkPrefixLimitV4 + connsPerNetworkPrefix := cl.connsPerNetworkPrefixV4 + limits := cl.connLimitPerSubnetV4 + connsPerLimit := cl.ip4connsPerLimit + isIP6 := ip.Is6() + if isIP6 { + networkPrefixLimits = cl.networkPrefixLimitV6 + connsPerNetworkPrefix = cl.connsPerNetworkPrefixV6 + limits = cl.connLimitPerSubnetV6 + connsPerLimit = cl.ip6connsPerLimit + } + + // Check Network Prefix limits first + if len(connsPerNetworkPrefix) == 0 && len(networkPrefixLimits) > 0 { + // Initialize the counts + connsPerNetworkPrefix = make([]int, len(networkPrefixLimits)) + if isIP6 { + cl.connsPerNetworkPrefixV6 = connsPerNetworkPrefix + } else { + cl.connsPerNetworkPrefixV4 = connsPerNetworkPrefix + } + } + + for i, limit := range networkPrefixLimits { + if limit.Network.Contains(ip) { + if connsPerNetworkPrefix[i]+1 > limit.ConnCount { + return false + } + connsPerNetworkPrefix[i]++ + // Done. If we find a match in the network prefix limits, we use + // that and don't use the general subnet limits. + return true + } + } + + if len(connsPerLimit) == 0 && len(limits) > 0 { + connsPerLimit = make([]map[string]int, len(limits)) + if isIP6 { + cl.ip6connsPerLimit = connsPerLimit + } else { + cl.ip4connsPerLimit = connsPerLimit + } + } + + for i, limit := range limits { + prefix, err := ip.Prefix(limit.PrefixLength) + if err != nil { + return false + } + masked := prefix.String() + counts, ok := connsPerLimit[i][masked] + if !ok { + if connsPerLimit[i] == nil { + connsPerLimit[i] = make(map[string]int) + } + connsPerLimit[i][masked] = 0 + } + if counts+1 > limit.ConnCount { + return false + } + } + + // All limit checks passed, now we update the counts + for i, limit := range limits { + prefix, _ := ip.Prefix(limit.PrefixLength) + masked := prefix.String() + connsPerLimit[i][masked]++ + } + + return true +} + +func (cl *connLimiter) rmConn(ip netip.Addr) { + cl.mu.Lock() + defer cl.mu.Unlock() + networkPrefixLimits := cl.networkPrefixLimitV4 + connsPerNetworkPrefix := cl.connsPerNetworkPrefixV4 + limits := cl.connLimitPerSubnetV4 + connsPerLimit := cl.ip4connsPerLimit + isIP6 := ip.Is6() + if isIP6 { + networkPrefixLimits = cl.networkPrefixLimitV6 + connsPerNetworkPrefix = cl.connsPerNetworkPrefixV6 + limits = cl.connLimitPerSubnetV6 + connsPerLimit = cl.ip6connsPerLimit + } + + // Check NetworkPrefix limits first + if len(connsPerNetworkPrefix) == 0 && len(networkPrefixLimits) > 0 { + // Initialize just in case. We should have already initialized in + // addConn, but if the callers calls rmConn first we don't want to panic + connsPerNetworkPrefix = make([]int, len(networkPrefixLimits)) + if isIP6 { + cl.connsPerNetworkPrefixV6 = connsPerNetworkPrefix + } else { + cl.connsPerNetworkPrefixV4 = connsPerNetworkPrefix + } + } + for i, limit := range networkPrefixLimits { + if limit.Network.Contains(ip) { + count := connsPerNetworkPrefix[i] + if count <= 0 { + log.Errorf("unexpected conn count for ip %s. Was this not added with addConn first?", ip) + return + } + connsPerNetworkPrefix[i]-- + // Done. We updated the count in the defined network prefix limit. + return + } + } + + if len(connsPerLimit) == 0 && len(limits) > 0 { + // Initialize just in case. We should have already initialized in + // addConn, but if the callers calls rmConn first we don't want to panic + connsPerLimit = make([]map[string]int, len(limits)) + if isIP6 { + cl.ip6connsPerLimit = connsPerLimit + } else { + cl.ip4connsPerLimit = connsPerLimit + } + } + + for i, limit := range limits { + prefix, err := ip.Prefix(limit.PrefixLength) + if err != nil { + // Unexpected since we should have seen this IP before in addConn + log.Errorf("unexpected error getting prefix: %v", err) + continue + } + masked := prefix.String() + counts, ok := connsPerLimit[i][masked] + if !ok || counts == 0 { + // Unexpected, but don't panic + log.Errorf("unexpected conn count for %s ok=%v count=%v", masked, ok, counts) + continue + } + connsPerLimit[i][masked]-- + if connsPerLimit[i][masked] <= 0 { + delete(connsPerLimit[i], masked) + } + } +} diff --git a/go-libp2p/p2p/host/resource-manager/conn_limiter_test.go b/go-libp2p/p2p/host/resource-manager/conn_limiter_test.go new file mode 100644 index 0000000..89ce5d5 --- /dev/null +++ b/go-libp2p/p2p/host/resource-manager/conn_limiter_test.go @@ -0,0 +1,214 @@ +package rcmgr + +import ( + "encoding/binary" + "net" + "net/netip" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestItLimits(t *testing.T) { + t.Run("IPv4", func(t *testing.T) { + ip, err := netip.ParseAddr("1.2.3.4") + require.NoError(t, err) + cl := newConnLimiter() + cl.connLimitPerSubnetV4[0].ConnCount = 1 + require.True(t, cl.addConn(ip)) + + // should fail the second time + require.False(t, cl.addConn(ip)) + + otherIP, err := netip.ParseAddr("1.2.3.5") + require.NoError(t, err) + require.True(t, cl.addConn(otherIP)) + }) + t.Run("IPv6", func(t *testing.T) { + ip, err := netip.ParseAddr("1:2:3:4::1") + require.NoError(t, err) + cl := newConnLimiter() + original := cl.connLimitPerSubnetV6[0].ConnCount + cl.connLimitPerSubnetV6[0].ConnCount = 1 + defer func() { + cl.connLimitPerSubnetV6[0].ConnCount = original + }() + require.True(t, cl.addConn(ip)) + + // should fail the second time + require.False(t, cl.addConn(ip)) + otherIPSameSubnet := netip.MustParseAddr("1:2:3:4::2") + require.False(t, cl.addConn(otherIPSameSubnet)) + + otherIP := netip.MustParseAddr("2:2:3:4::2") + require.True(t, cl.addConn(otherIP)) + }) + + t.Run("IPv6 with multiple limits", func(t *testing.T) { + cl := newConnLimiter() + for i := 0; i < defaultMaxConcurrentConns; i++ { + ip := net.ParseIP("ff:2:3:4::1") + binary.BigEndian.PutUint16(ip[14:], uint16(i)) + ipAddr := netip.MustParseAddr(ip.String()) + require.True(t, cl.addConn(ipAddr)) + } + + // Next one should fail + ip := net.ParseIP("ff:2:3:4::1") + binary.BigEndian.PutUint16(ip[14:], uint16(defaultMaxConcurrentConns+1)) + require.False(t, cl.addConn(netip.MustParseAddr(ip.String()))) + + // But on a different root subnet should work + otherIP := netip.MustParseAddr("ffef:2:3::1") + require.True(t, cl.addConn(otherIP)) + + // But too many on the next subnet limit will fail too + for i := 0; i < defaultMaxConcurrentConns*8; i++ { + ip := net.ParseIP("ffef:2:3:4::1") + binary.BigEndian.PutUint16(ip[5:7], uint16(i)) + ipAddr := netip.MustParseAddr(ip.String()) + require.True(t, cl.addConn(ipAddr)) + } + + ip = net.ParseIP("ffef:2:3:4::1") + binary.BigEndian.PutUint16(ip[5:7], uint16(defaultMaxConcurrentConns*8+1)) + ipAddr := netip.MustParseAddr(ip.String()) + require.False(t, cl.addConn(ipAddr)) + }) + + t.Run("IPv4 with localhost", func(t *testing.T) { + cl := &connLimiter{ + networkPrefixLimitV4: DefaultNetworkPrefixLimitV4, + connLimitPerSubnetV4: []ConnLimitPerSubnet{ + {PrefixLength: 0, ConnCount: 1}, // 1 connection for the whole IPv4 space + }, + } + + ip := netip.MustParseAddr("1.2.3.4") + require.True(t, cl.addConn(ip)) + + ip = netip.MustParseAddr("4.3.2.1") + // should fail the second time, we only allow 1 connection for the whole IPv4 space + require.False(t, cl.addConn(ip)) + + ip = netip.MustParseAddr("127.0.0.1") + // Succeeds because we defined an explicit limit for the loopback subnet + require.True(t, cl.addConn(ip)) + }) +} + +func genIP(data *[]byte) (netip.Addr, bool) { + if len(*data) < 1 { + return netip.Addr{}, false + } + + genIP6 := (*data)[0]&0x01 == 1 + bytesRequired := 4 + if genIP6 { + bytesRequired = 16 + } + + if len((*data)[1:]) < bytesRequired { + return netip.Addr{}, false + } + + *data = (*data)[1:] + ip, ok := netip.AddrFromSlice((*data)[:bytesRequired]) + *data = (*data)[bytesRequired:] + return ip, ok +} + +func FuzzConnLimiter(f *testing.F) { + // The goal is to try to enter a state where the count is incorrectly 0 + f.Fuzz(func(t *testing.T, data []byte) { + ips := make([]netip.Addr, 0, len(data)/5) + for { + ip, ok := genIP(&data) + if !ok { + break + } + ips = append(ips, ip) + } + + cl := newConnLimiter() + addedConns := make([]netip.Addr, 0, len(ips)) + for _, ip := range ips { + if cl.addConn(ip) { + addedConns = append(addedConns, ip) + } + } + + addedCount := 0 + for _, ip := range cl.ip4connsPerLimit { + for _, count := range ip { + addedCount += count + } + } + for _, ip := range cl.ip6connsPerLimit { + for _, count := range ip { + addedCount += count + } + } + for _, count := range cl.connsPerNetworkPrefixV4 { + addedCount += count + } + for _, count := range cl.connsPerNetworkPrefixV6 { + addedCount += count + } + if addedCount == 0 && len(addedConns) > 0 { + t.Fatalf("added count: %d", addedCount) + } + + for _, ip := range addedConns { + cl.rmConn(ip) + } + + leftoverCount := 0 + for _, ip := range cl.ip4connsPerLimit { + for _, count := range ip { + leftoverCount += count + } + } + for _, ip := range cl.ip6connsPerLimit { + for _, count := range ip { + leftoverCount += count + } + } + for _, count := range cl.connsPerNetworkPrefixV4 { + addedCount += count + } + for _, count := range cl.connsPerNetworkPrefixV6 { + addedCount += count + } + if leftoverCount != 0 { + t.Fatalf("leftover count: %d", leftoverCount) + } + }) +} + +func TestSortedNetworkPrefixLimits(t *testing.T) { + npLimits := []NetworkPrefixLimit{ + { + Network: netip.MustParsePrefix("1.2.0.0/16"), + }, + { + Network: netip.MustParsePrefix("1.2.3.0/28"), + }, + { + Network: netip.MustParsePrefix("1.2.3.4/32"), + }, + } + npLimits = sortNetworkPrefixes(npLimits) + sorted := []NetworkPrefixLimit{ + { + Network: netip.MustParsePrefix("1.2.3.4/32"), + }, + { + Network: netip.MustParsePrefix("1.2.3.0/28"), + }, + { + Network: netip.MustParsePrefix("1.2.0.0/16"), + }, + } + require.EqualValues(t, sorted, npLimits) +} diff --git a/go-libp2p/p2p/host/resource-manager/docs/allowlist.md b/go-libp2p/p2p/host/resource-manager/docs/allowlist.md index 4ada09c..6cf88e0 100644 --- a/go-libp2p/p2p/host/resource-manager/docs/allowlist.md +++ b/go-libp2p/p2p/host/resource-manager/docs/allowlist.md @@ -47,7 +47,7 @@ creates the connection resource scope using the allowlisted specific system and transient resource scopes. If it wasn't an allowlisted multiaddr it fails as before. -When an allowlisted connection is tied to a peer id and transfered with +When an allowlisted connection is tied to a peer id and transferred with `ConnManagementScope.SetPeer`, we check if that peer id matches the expected value in the allowlist (if it exists). If it does not match, we attempt to transfer this resource to the normal system and peer scope. If that transfer diff --git a/go-libp2p/p2p/host/resource-manager/extapi.go b/go-libp2p/p2p/host/resource-manager/extapi.go index 03edcd7..415d7f8 100644 --- a/go-libp2p/p2p/host/resource-manager/extapi.go +++ b/go-libp2p/p2p/host/resource-manager/extapi.go @@ -145,3 +145,7 @@ func (r *resourceManager) Stat() (result ResourceManagerStat) { return result } + +func (r *resourceManager) GetConnLimit() int { + return r.limits.GetSystemLimits().GetConnTotalLimit() +} diff --git a/go-libp2p/p2p/host/resource-manager/limit_test.go b/go-libp2p/p2p/host/resource-manager/limit_test.go index 68d6bf2..8d9f391 100644 --- a/go-libp2p/p2p/host/resource-manager/limit_test.go +++ b/go-libp2p/p2p/host/resource-manager/limit_test.go @@ -110,7 +110,6 @@ func TestScaling(t *testing.T) { require.Equal(t, 20+4*2, scaled.service["B"].Streams) require.Equal(t, int64(200+4*3), scaled.service["B"].Memory) require.Equal(t, 400, scaled.service["B"].FD) - }) } @@ -157,7 +156,7 @@ func TestJSONMarshalling(t *testing.T) { jsonEncoded, err := json.Marshal(bl) require.NoError(t, err) - require.Equal(t, string(jsonEncoded), `{"StreamsInbound":10,"StreamsOutbound":"blockAll","Conns":10,"ConnsOutbound":"unlimited","Memory":"unlimited"}`) + require.Equal(t, `{"StreamsInbound":10,"StreamsOutbound":"blockAll","Conns":10,"ConnsOutbound":"unlimited","Memory":"unlimited"}`, string(jsonEncoded)) // Roundtrip var blDecoded ResourceLimits @@ -175,7 +174,7 @@ func TestJSONRoundTripInt64(t *testing.T) { jsonEncoded, err := json.Marshal(bl) require.NoError(t, err) - require.Equal(t, string(jsonEncoded), `{"Memory":"9223372036854775807"}`) + require.Equal(t, `{"Memory":"9223372036854775807"}`, string(jsonEncoded)) // Roundtrip var blDecoded ResourceLimits diff --git a/go-libp2p/p2p/host/resource-manager/rcmgr.go b/go-libp2p/p2p/host/resource-manager/rcmgr.go index 188a171..2eb1b3a 100644 --- a/go-libp2p/p2p/host/resource-manager/rcmgr.go +++ b/go-libp2p/p2p/host/resource-manager/rcmgr.go @@ -3,6 +3,7 @@ package rcmgr import ( "context" "fmt" + "net/netip" "strings" "sync" "time" @@ -13,6 +14,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" ) var log = logging.Logger("rcmgr") @@ -20,6 +22,8 @@ var log = logging.Logger("rcmgr") type resourceManager struct { limits Limiter + connLimiter *connLimiter + trace *trace metrics *metrics disableMetrics bool @@ -103,6 +107,7 @@ type connectionScope struct { rcmgr *resourceManager peer *peerScope endpoint multiaddr.Multiaddr + ip netip.Addr } var _ network.ConnScope = (*connectionScope)(nil) @@ -129,11 +134,12 @@ type Option func(*resourceManager) error func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager, error) { allowlist := newAllowlist() r := &resourceManager{ - limits: limits, - allowlist: &allowlist, - svc: make(map[string]*serviceScope), - proto: make(map[protocol.ID]*protocolScope), - peer: make(map[peer.ID]*peerScope), + limits: limits, + connLimiter: newConnLimiter(), + allowlist: &allowlist, + svc: make(map[string]*serviceScope), + proto: make(map[protocol.ID]*protocolScope), + peer: make(map[peer.ID]*peerScope), } for _, opt := range opts { @@ -142,6 +148,28 @@ func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager } } + registeredConnLimiterPrefixes := make(map[string]struct{}) + for _, npLimit := range r.connLimiter.networkPrefixLimitV4 { + registeredConnLimiterPrefixes[npLimit.Network.String()] = struct{}{} + } + for _, npLimit := range r.connLimiter.networkPrefixLimitV6 { + registeredConnLimiterPrefixes[npLimit.Network.String()] = struct{}{} + } + for _, network := range allowlist.allowedNetworks { + prefix, err := netip.ParsePrefix(network.String()) + if err != nil { + log.Debugf("failed to parse prefix from allowlist %s, %s", network, err) + continue + } + if _, ok := registeredConnLimiterPrefixes[prefix.String()]; !ok { + // connlimiter doesn't know about this network. Let's fix that + r.connLimiter.addNetworkPrefixLimit(prefix.Addr().Is6(), NetworkPrefixLimit{ + Network: prefix, + ConnCount: r.limits.GetAllowlistedSystemLimits().GetConnTotalLimit(), + }) + } + } + if !r.disableMetrics { var sr TraceReporter sr, err := NewStatsTraceReporter() @@ -310,12 +338,37 @@ func (r *resourceManager) nextStreamId() int64 { return r.streamId } +// OpenConnectionNoIP is deprecated and will be removed in the next release +func (r *resourceManager) OpenConnectionNoIP(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr) (network.ConnManagementScope, error) { + return r.openConnection(dir, usefd, endpoint, netip.Addr{}) +} + func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr) (network.ConnManagementScope, error) { + ip, err := manet.ToIP(endpoint) + if err != nil { + // No IP address + return r.openConnection(dir, usefd, endpoint, netip.Addr{}) + } + + ipAddr, ok := netip.AddrFromSlice(ip) + if !ok { + return nil, fmt.Errorf("failed to convert ip to netip.Addr") + } + return r.openConnection(dir, usefd, endpoint, ipAddr) +} + +func (r *resourceManager) openConnection(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr, ip netip.Addr) (network.ConnManagementScope, error) { + if ip.IsValid() { + if ok := r.connLimiter.addConn(ip); !ok { + return nil, fmt.Errorf("connections per ip limit exceeded for %s", endpoint) + } + } + var conn *connectionScope - conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint) + conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint, ip) err := conn.AddConn(dir, usefd) - if err != nil { + if err != nil && ip.IsValid() { // Try again if this is an allowlisted connection // Failed to open connection, let's see if this was allowlisted and try again allowed := r.allowlist.Allowed(endpoint) @@ -476,7 +529,7 @@ func newPeerScope(p peer.ID, limit Limit, rcmgr *resourceManager) *peerScope { } } -func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr) *connectionScope { +func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr, ip netip.Addr) *connectionScope { return &connectionScope{ resourceScope: newResourceScope(limit, []*resourceScope{rcmgr.transient.resourceScope, rcmgr.system.resourceScope}, @@ -485,6 +538,7 @@ func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *r usefd: usefd, rcmgr: rcmgr, endpoint: endpoint, + ip: ip, } } @@ -643,6 +697,18 @@ func (s *connectionScope) PeerScope() network.PeerScope { return s.peer } +func (s *connectionScope) Done() { + s.Lock() + defer s.Unlock() + if s.done { + return + } + if s.ip.IsValid() { + s.rcmgr.connLimiter.rmConn(s.ip) + } + s.resourceScope.doneUnlocked() +} + // transferAllowedToStandard transfers this connection scope from being part of // the allowlist set of scopes to being part of the standard set of scopes. // Happens when we first allowlisted this connection due to its IP, but later diff --git a/go-libp2p/p2p/host/resource-manager/rcmgr_test.go b/go-libp2p/p2p/host/resource-manager/rcmgr_test.go index 61d53be..bf79f7a 100644 --- a/go-libp2p/p2p/host/resource-manager/rcmgr_test.go +++ b/go-libp2p/p2p/host/resource-manager/rcmgr_test.go @@ -1,12 +1,14 @@ package rcmgr import ( + "net/netip" "testing" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/test" + "github.com/stretchr/testify/require" "github.com/multiformats/go-multiaddr" ) @@ -1051,3 +1053,61 @@ func TestResourceManagerWithAllowlist(t *testing.T) { t.Fatal(err) } } + +// TestAllowlistAndConnLimiterPlayNice checks that the connLimiter learns about network prefix limits from the allowlist. +func TestAllowlistAndConnLimiterPlayNice(t *testing.T) { + limits := DefaultLimits.AutoScale() + limits.allowlistedSystem.Conns = 8 + limits.allowlistedSystem.ConnsInbound = 8 + limits.allowlistedSystem.ConnsOutbound = 8 + t.Run("IPv4", func(t *testing.T) { + rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{ + multiaddr.StringCast("/ip4/1.2.3.0/ipcidr/24"), + }), WithNetworkPrefixLimit([]NetworkPrefixLimit{}, []NetworkPrefixLimit{})) + if err != nil { + t.Fatal(err) + } + defer rcmgr.Close() + + // The connLimiter should have the allowlisted network prefix + require.Equal(t, netip.MustParsePrefix("1.2.3.0/24"), rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV4[0].Network) + + // The connLimiter should use the limit from the allowlist + require.Equal(t, 8, rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV4[0].ConnCount) + }) + t.Run("IPv6", func(t *testing.T) { + rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{ + multiaddr.StringCast("/ip6/1:2:3::/ipcidr/58"), + }), WithNetworkPrefixLimit([]NetworkPrefixLimit{}, []NetworkPrefixLimit{})) + if err != nil { + t.Fatal(err) + } + defer rcmgr.Close() + + // The connLimiter should have the allowlisted network prefix + require.Equal(t, netip.MustParsePrefix("1:2:3::/58"), rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV6[0].Network) + + // The connLimiter should use the limit from the allowlist + require.Equal(t, 8, rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV6[0].ConnCount) + }) + + t.Run("Does not override if you set a limit directly", func(t *testing.T) { + rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{ + multiaddr.StringCast("/ip4/1.2.3.0/ipcidr/24"), + }), WithNetworkPrefixLimit([]NetworkPrefixLimit{ + {Network: netip.MustParsePrefix("1.2.3.0/24"), ConnCount: 1}, + }, []NetworkPrefixLimit{})) + if err != nil { + t.Fatal(err) + } + defer rcmgr.Close() + + // The connLimiter should have it because we set it + require.Equal(t, netip.MustParsePrefix("1.2.3.0/24"), rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV4[0].Network) + // should only have one network prefix limit + require.Equal(t, 1, len(rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV4)) + + // The connLimiter should use the limit we defined explicitly + require.Equal(t, 1, rcmgr.(*resourceManager).connLimiter.networkPrefixLimitV4[0].ConnCount) + }) +} diff --git a/go-libp2p/p2p/host/resource-manager/scope.go b/go-libp2p/p2p/host/resource-manager/scope.go index 60089c3..8a6bc23 100644 --- a/go-libp2p/p2p/host/resource-manager/scope.go +++ b/go-libp2p/p2p/host/resource-manager/scope.go @@ -118,12 +118,10 @@ func (rc *resources) checkMemory(rsvp int64, prio uint8) error { threshold, mulOk := mulInt64WithOverflow(1+int64(prio), limit) if !mulOk { thresholdBig := big.NewInt(limit) - thresholdBig = thresholdBig.Mul(thresholdBig, big.NewInt(1+int64(prio))) + thresholdBig.Mul(thresholdBig, big.NewInt(1+int64(prio))) thresholdBig.Rsh(thresholdBig, 8) // Divide 256 - if !thresholdBig.IsInt64() { - // Shouldn't happen since the threshold can only be <= limit - threshold = limit - } + // necessarily a Int64 since we multiplied a int64 != MaxInt64 with + // a uint8+1 (max 255+1 = 256) and divided by 256 threshold = thresholdBig.Int64() } else { threshold = threshold / 256 @@ -745,10 +743,13 @@ func (s *resourceScope) Done() { s.Lock() defer s.Unlock() + s.doneUnlocked() +} + +func (s *resourceScope) doneUnlocked() { if s.done { return } - stat := s.rc.stat() if s.owner != nil { s.owner.ReleaseResources(stat) diff --git a/go-libp2p/p2p/host/resource-manager/scope_test.go b/go-libp2p/p2p/host/resource-manager/scope_test.go index 0464cb0..7bf7ff7 100644 --- a/go-libp2p/p2p/host/resource-manager/scope_test.go +++ b/go-libp2p/p2p/host/resource-manager/scope_test.go @@ -74,7 +74,7 @@ func TestCheckMemory(t *testing.T) { limit = 1024 } currentMem = (currentMem % limit) // We can't have reserved more than our limit - res = (res >> 14) // We won't resonably ever have a reservation > 2^50 + res = (res >> 14) // We won't reasonably ever have a reservation > 2^50 rc := resources{limit: &BaseLimit{ Memory: int64(limit), StreamsInbound: 1, @@ -88,7 +88,7 @@ func TestCheckMemory(t *testing.T) { rc.memory = int64(currentMem) priShift = (priShift % 9) - // Check different priorties at 2^0, 2^1,...2^8. This lets our math be correct in the check below (and avoid overflows). + // Check different priorities at 2^0, 2^1,...2^8. This lets our math be correct in the check below (and avoid overflows). pri := uint8((1 << priShift) - 1) err := rc.checkMemory(int64(res), pri) @@ -97,7 +97,7 @@ func TestCheckMemory(t *testing.T) { return true } - return (err != nil) == (uint64(res)+uint64(rc.memory) > (uint64(limit) >> uint64(8-priShift))) + return (err != nil) == (res+uint64(rc.memory) > (limit >> uint64(8-priShift))) } require.NoError(t, quick.Check(f, nil)) diff --git a/go-libp2p/p2p/host/routed/routed.go b/go-libp2p/p2p/host/routed/routed.go index eb8e58e..8248e50 100644 --- a/go-libp2p/p2p/host/routed/routed.go +++ b/go-libp2p/p2p/host/routed/routed.go @@ -48,8 +48,10 @@ func Wrap(h host.Host, r Routing) *RoutedHost { func (rh *RoutedHost) Connect(ctx context.Context, pi peer.AddrInfo) error { // first, check if we're already connected unless force direct dial. forceDirect, _ := network.GetForceDirectDial(ctx) + canUseLimitedConn, _ := network.GetAllowLimitedConn(ctx) if !forceDirect { - if rh.Network().Connectedness(pi.ID) == network.Connected { + connectedness := rh.Network().Connectedness(pi.ID) + if connectedness == network.Connected || (canUseLimitedConn && connectedness == network.Limited) { return nil } } diff --git a/go-libp2p/p2p/http/example_test.go b/go-libp2p/p2p/http/example_test.go new file mode 100644 index 0000000..ca87fe4 --- /dev/null +++ b/go-libp2p/p2p/http/example_test.go @@ -0,0 +1,359 @@ +package libp2phttp_test + +import ( + "fmt" + "io" + "log" + "net" + "net/http" + "strings" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/peer" + libp2phttp "github.com/libp2p/go-libp2p/p2p/http" + ma "github.com/multiformats/go-multiaddr" +) + +func ExampleHost_withAStockGoHTTPClient() { + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + // A server with a simple echo protocol + server.SetHTTPHandler("/echo/1.0.0", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "application/octet-stream") + io.Copy(w, r.Body) + })) + go server.Serve() + defer server.Close() + + var serverHTTPPort string + var err error + for _, a := range server.Addrs() { + serverHTTPPort, err = a.ValueForProtocol(ma.P_TCP) + if err == nil { + break + } + } + if err != nil { + log.Fatal(err) + } + + // Make an HTTP request using the Go standard library. + resp, err := http.Post("http://127.0.0.1:"+serverHTTPPort+"/echo/1.0.0/", "application/octet-stream", strings.NewReader("Hello HTTP")) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(body)) + + // Output: Hello HTTP +} + +func ExampleHost_listenOnHTTPTransportAndStreams() { + serverStreamHost, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1")) + if err != nil { + log.Fatal(err) + } + defer serverStreamHost.Close() + + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + StreamHost: serverStreamHost, + } + go server.Serve() + defer server.Close() + + for _, a := range server.Addrs() { + _, transport := ma.SplitLast(a) + fmt.Printf("Server listening on transport: %s\n", transport) + } + // Output: Server listening on transport: /quic-v1 + // Server listening on transport: /http +} + +func ExampleHost_overLibp2pStreams() { + serverStreamHost, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1")) + if err != nil { + log.Fatal(err) + } + + server := libp2phttp.Host{ + StreamHost: serverStreamHost, + } + + // A server with a simple echo protocol + server.SetHTTPHandler("/echo/1.0.0", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "application/octet-stream") + io.Copy(w, r.Body) + })) + go server.Serve() + defer server.Close() + + clientStreamHost, err := libp2p.New(libp2p.NoListenAddrs) + if err != nil { + log.Fatal(err) + } + + client := libp2phttp.Host{StreamHost: clientStreamHost} + + // Make an HTTP request using the Go standard library, but over libp2p + // streams. If the server were listening on an HTTP transport, this could + // also make the request over the HTTP transport. + httpClient, err := client.NamespacedClient("/echo/1.0.0", peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + + // Only need to Post to "/" because this client is namespaced to the "/echo/1.0.0" protocol. + resp, err := httpClient.Post("/", "application/octet-stream", strings.NewReader("Hello HTTP")) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + fmt.Println(string(body)) + + // Output: Hello HTTP +} + +func ExampleHost_Serve() { + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50221/http")}, + } + + go server.Serve() + defer server.Close() + + fmt.Println(server.Addrs()) + + // Output: [/ip4/127.0.0.1/tcp/50221/http] +} + +func ExampleHost_SetHTTPHandler() { + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + port, err := server.Addrs()[0].ValueForProtocol(ma.P_TCP) + if err != nil { + log.Fatal(err) + } + + resp, err := http.Get("http://127.0.0.1:" + port + "/hello/1/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHost_SetHTTPHandlerAtPath() { + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + server.SetHTTPHandlerAtPath("/hello/1", "/other-place/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + port, err := server.Addrs()[0].ValueForProtocol(ma.P_TCP) + if err != nil { + log.Fatal(err) + } + + resp, err := http.Get("http://127.0.0.1:" + port + "/other-place/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHost_NamespacedClient() { + var client libp2phttp.Host + + // Create the server + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + server.SetHTTPHandlerAtPath("/hello/1", "/other-place/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Client that is namespaced to this protocol. + httpClient, err := client.NamespacedClient("/hello/1", peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + resp, err := httpClient.Get("/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHost_NamespaceRoundTripper() { + var client libp2phttp.Host + + // Create the server + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Roundtripper for the server + rt, err := client.NewConstrainedRoundTripper(peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + // Namespace this roundtripper to a specific protocol + rt, err = client.NamespaceRoundTripper(rt, "/hello/1", server.PeerID()) + if err != nil { + log.Fatal(err) + } + + resp, err := (&http.Client{Transport: rt}).Get("/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHost_NewConstrainedRoundTripper() { + var client libp2phttp.Host + + // Create the server + server := libp2phttp.Host{ + InsecureAllowHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Roundtripper for the server + rt, err := client.NewConstrainedRoundTripper(peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + resp, err := (&http.Client{Transport: rt}).Get("/hello/1") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleWellKnownHandler() { + var h libp2phttp.WellKnownHandler + h.AddProtocolMeta("/hello/1", libp2phttp.ProtocolMeta{ + Path: "/hello-path/", + }) + + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatal(err) + } + + defer listener.Close() + // Serve the well-known resource. Note, this is handled automatically if you use the libp2phttp.Host. + go http.Serve(listener, &h) + + // Get the well-known resource + resp, err := http.Get("http://" + listener.Addr().String() + libp2phttp.WellKnownProtocols) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + // Output: {"/hello/1":{"path":"/hello-path/"}} + +} diff --git a/go-libp2p/p2p/http/libp2phttp.go b/go-libp2p/p2p/http/libp2phttp.go new file mode 100644 index 0000000..5ff025e --- /dev/null +++ b/go-libp2p/p2p/http/libp2phttp.go @@ -0,0 +1,918 @@ +// HTTP semantics with libp2p. Can use a libp2p stream transport or stock HTTP +// transports. This API is experimental and will likely change soon. Implements [libp2p spec #508](https://github.com/libp2p/specs/pull/508). +package libp2phttp + +import ( + "bufio" + "context" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "net/http" + "net/url" + "strconv" + "strings" + "sync" + "time" + + lru "github.com/hashicorp/golang-lru/v2" + logging "github.com/ipfs/go-log/v2" + host "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/core/protocol" + gostream "github.com/libp2p/go-libp2p/p2p/net/gostream" + ma "github.com/multiformats/go-multiaddr" +) + +var log = logging.Logger("libp2phttp") + +var WellKnownRequestTimeout = 30 * time.Second + +const ProtocolIDForMultistreamSelect = "/http/1.1" +const WellKnownProtocols = "/.well-known/libp2p/protocols" + +// LegacyWellKnownProtocols refer to a the well-known resource used in an early +// draft of the libp2p+http spec. Some users have deployed this, and need backwards compatibility. +// Hopefully we can phase this out in the future. Context: https://github.com/libp2p/go-libp2p/pull/2797 +const LegacyWellKnownProtocols = "/.well-known/libp2p" + +const peerMetadataLimit = 8 << 10 // 8KB +const peerMetadataLRUSize = 256 // How many different peer's metadata to keep in our LRU cache + +// ProtocolMeta is metadata about a protocol. +type ProtocolMeta struct { + // Path defines the HTTP Path prefix used for this protocol + Path string `json:"path"` +} + +type PeerMeta map[protocol.ID]ProtocolMeta + +// WellKnownHandler is an http.Handler that serves the well-known resource +type WellKnownHandler struct { + wellknownMapMu sync.Mutex + wellKnownMapping PeerMeta + wellKnownCache []byte +} + +// streamHostListen returns a net.Listener that listens on libp2p streams for HTTP/1.1 messages. +func streamHostListen(streamHost host.Host) (net.Listener, error) { + return gostream.Listen(streamHost, ProtocolIDForMultistreamSelect) +} + +func (h *WellKnownHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Check if the requests accepts JSON + accepts := r.Header.Get("Accept") + if accepts != "" && !(strings.Contains(accepts, "application/json") || strings.Contains(accepts, "*/*")) { + http.Error(w, "Only application/json is supported", http.StatusNotAcceptable) + return + } + + if r.Method != http.MethodGet { + http.Error(w, "Only GET requests are supported", http.StatusMethodNotAllowed) + return + } + + // Return a JSON object with the well-known protocols + h.wellknownMapMu.Lock() + mapping := h.wellKnownCache + var err error + if mapping == nil { + mapping, err = json.Marshal(h.wellKnownMapping) + if err == nil { + h.wellKnownCache = mapping + } + } + h.wellknownMapMu.Unlock() + if err != nil { + http.Error(w, "Marshal error", http.StatusInternalServerError) + return + } + w.Header().Add("Content-Type", "application/json") + w.Header().Add("Content-Length", strconv.Itoa(len(mapping))) + w.Write(mapping) +} + +func (h *WellKnownHandler) AddProtocolMeta(p protocol.ID, protocolMeta ProtocolMeta) { + h.wellknownMapMu.Lock() + if h.wellKnownMapping == nil { + h.wellKnownMapping = make(map[protocol.ID]ProtocolMeta) + } + h.wellKnownMapping[p] = protocolMeta + h.wellKnownCache = nil + h.wellknownMapMu.Unlock() +} + +func (h *WellKnownHandler) RemoveProtocolMeta(p protocol.ID) { + h.wellknownMapMu.Lock() + if h.wellKnownMapping != nil { + delete(h.wellKnownMapping, p) + } + h.wellKnownCache = nil + h.wellknownMapMu.Unlock() +} + +// Host is a libp2p host for request/responses with HTTP semantics. This is +// in contrast to a stream-oriented host like the core host.Host interface. Its +// zero-value (&Host{}) is usable. Do not copy by value. +// See examples for usage. +// +// Warning, this is experimental. The API will likely change. +type Host struct { + // StreamHost is a stream based libp2p host used to do HTTP over libp2p streams. May be nil + StreamHost host.Host + // ListenAddrs are the requested addresses to listen on. Multiaddrs must be + // valid HTTP(s) multiaddr. Only multiaddrs for an HTTP transport are + // supported (must end with /http or /https). + ListenAddrs []ma.Multiaddr + // TLSConfig is the TLS config for the server to use + TLSConfig *tls.Config + // InsecureAllowHTTP indicates if the server is allowed to serve unencrypted + // HTTP requests over TCP. + InsecureAllowHTTP bool + // ServeMux is the http.ServeMux used by the server to serve requests. If + // nil, a new serve mux will be created. Users may manually add handlers to + // this mux instead of using `SetHTTPHandler`, but if they do, they should + // also update the WellKnownHandler's protocol mapping. + ServeMux *http.ServeMux + initializeServeMux sync.Once + + // DefaultClientRoundTripper is the default http.RoundTripper for clients to + // use when making requests over an HTTP transport. This must be an + // `*http.Transport` type so that the transport can be cloned and the + // `TLSClientConfig` field can be configured. If unset, it will create a new + // `http.Transport` on first use. + DefaultClientRoundTripper *http.Transport + + // WellKnownHandler is the http handler for the well-known + // resource. It is responsible for sharing this node's protocol metadata + // with other nodes. Users only care about this if they set their own + // ServeMux with pre-existing routes. By default, new protocols are added + // here when a user calls `SetHTTPHandler` or `SetHTTPHandlerAtPath`. + WellKnownHandler WellKnownHandler + + // EnableCompatibilityWithLegacyWellKnownEndpoint allows compatibility with + // an older version of the spec that defined the well-known resource as: + // .well-known/libp2p. + // For servers, this means hosting the well-known resource at both the + // legacy and current paths. + // For clients it means making two parallel requests and picking the first one that succeeds. + // + // Long term this should be deprecated once enough users have upgraded to a + // newer go-libp2p version and we can remove all this code. + EnableCompatibilityWithLegacyWellKnownEndpoint bool + + // peerMetadata is an LRU cache of a peer's well-known protocol map. + peerMetadata *lru.Cache[peer.ID, PeerMeta] + // createHTTPTransport is used to lazily create the httpTransport in a thread-safe way. + createHTTPTransport sync.Once + // createDefaultClientRoundTripper is used to lazily create the default + // client round tripper in a thread-safe way. + createDefaultClientRoundTripper sync.Once + httpTransport *httpTransport +} + +type httpTransport struct { + listenAddrs []ma.Multiaddr + listeners []net.Listener + closeListeners chan struct{} + waitingForListeners chan struct{} +} + +func newPeerMetadataCache() *lru.Cache[peer.ID, PeerMeta] { + peerMetadata, err := lru.New[peer.ID, PeerMeta](peerMetadataLRUSize) + if err != nil { + // Only happens if size is < 1. We make sure to not do that, so this should never happen. + panic(err) + } + return peerMetadata +} + +func (h *Host) httpTransportInit() { + h.createHTTPTransport.Do(func() { + h.httpTransport = &httpTransport{ + closeListeners: make(chan struct{}), + waitingForListeners: make(chan struct{}), + } + }) +} + +func (h *Host) serveMuxInit() { + h.initializeServeMux.Do(func() { + if h.ServeMux == nil { + h.ServeMux = http.NewServeMux() + } + }) +} + +func (h *Host) Addrs() []ma.Multiaddr { + h.httpTransportInit() + <-h.httpTransport.waitingForListeners + return h.httpTransport.listenAddrs +} + +// ID returns the peer ID of the underlying stream host, or the zero value if there is no stream host. +func (h *Host) PeerID() peer.ID { + if h.StreamHost != nil { + return h.StreamHost.ID() + } + return "" +} + +var ErrNoListeners = errors.New("nothing to listen on") + +func (h *Host) setupListeners(listenerErrCh chan error) error { + for _, addr := range h.ListenAddrs { + parsedAddr := parseMultiaddr(addr) + // resolve the host + ipaddr, err := net.ResolveIPAddr("ip", parsedAddr.host) + if err != nil { + return err + } + + host := ipaddr.String() + l, err := net.Listen("tcp", host+":"+parsedAddr.port) + if err != nil { + return err + } + h.httpTransport.listeners = append(h.httpTransport.listeners, l) + + // get resolved port + _, port, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return err + } + + var listenAddr ma.Multiaddr + if parsedAddr.useHTTPS && parsedAddr.sni != "" && parsedAddr.sni != host { + listenAddr = ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/%s/tls/sni/%s/http", host, port, parsedAddr.sni)) + } else { + scheme := "http" + if parsedAddr.useHTTPS { + scheme = "https" + } + listenAddr = ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/%s/%s", host, port, scheme)) + } + + if parsedAddr.useHTTPS { + go func() { + srv := http.Server{ + Handler: h.ServeMux, + TLSConfig: h.TLSConfig, + } + listenerErrCh <- srv.ServeTLS(l, "", "") + }() + h.httpTransport.listenAddrs = append(h.httpTransport.listenAddrs, listenAddr) + } else if h.InsecureAllowHTTP { + go func() { + listenerErrCh <- http.Serve(l, h.ServeMux) + }() + h.httpTransport.listenAddrs = append(h.httpTransport.listenAddrs, listenAddr) + } else { + // We are not serving insecure HTTP + log.Warnf("Not serving insecure HTTP on %s. Prefer an HTTPS endpoint.", listenAddr) + } + } + return nil +} + +// Serve starts the HTTP transport listeners. Always returns a non-nil error. +// If there are no listeners, returns ErrNoListeners. +func (h *Host) Serve() error { + // assert that each addr contains a /http component + for _, addr := range h.ListenAddrs { + _, isHTTP := normalizeHTTPMultiaddr(addr) + if !isHTTP { + return fmt.Errorf("address %s does not contain a /http or /https component", addr) + } + } + + h.serveMuxInit() + h.ServeMux.Handle(WellKnownProtocols, &h.WellKnownHandler) + if h.EnableCompatibilityWithLegacyWellKnownEndpoint { + h.ServeMux.Handle(LegacyWellKnownProtocols, &h.WellKnownHandler) + } + + h.httpTransportInit() + + closedWaitingForListeners := false + defer func() { + if !closedWaitingForListeners { + close(h.httpTransport.waitingForListeners) + } + }() + + if len(h.ListenAddrs) == 0 && h.StreamHost == nil { + return ErrNoListeners + } + + h.httpTransport.listeners = make([]net.Listener, 0, len(h.ListenAddrs)+1) // +1 for stream host + + streamHostAddrsCount := 0 + if h.StreamHost != nil { + streamHostAddrsCount = len(h.StreamHost.Addrs()) + } + h.httpTransport.listenAddrs = make([]ma.Multiaddr, 0, len(h.ListenAddrs)+streamHostAddrsCount) + + errCh := make(chan error) + + if h.StreamHost != nil { + listener, err := streamHostListen(h.StreamHost) + if err != nil { + return err + } + h.httpTransport.listeners = append(h.httpTransport.listeners, listener) + h.httpTransport.listenAddrs = append(h.httpTransport.listenAddrs, h.StreamHost.Addrs()...) + + go func() { + errCh <- http.Serve(listener, connectionCloseHeaderMiddleware(h.ServeMux)) + }() + } + + closeAllListeners := func() { + for _, l := range h.httpTransport.listeners { + l.Close() + } + } + + err := h.setupListeners(errCh) + if err != nil { + closeAllListeners() + return err + } + + close(h.httpTransport.waitingForListeners) + closedWaitingForListeners = true + + if len(h.httpTransport.listeners) == 0 || len(h.httpTransport.listenAddrs) == 0 { + closeAllListeners() + return ErrNoListeners + } + + expectedErrCount := len(h.httpTransport.listeners) + select { + case <-h.httpTransport.closeListeners: + case err = <-errCh: + expectedErrCount-- + } + + // Close all listeners + closeAllListeners() + for i := 0; i < expectedErrCount; i++ { + <-errCh + } + close(errCh) + + return err +} + +func (h *Host) Close() error { + h.httpTransportInit() + close(h.httpTransport.closeListeners) + return nil +} + +// SetHTTPHandler sets the HTTP handler for a given protocol. Automatically +// manages the well-known resource mapping. +// http.StripPrefix is called on the handler, so the handler will be unaware of +// its prefix path. +func (h *Host) SetHTTPHandler(p protocol.ID, handler http.Handler) { + h.SetHTTPHandlerAtPath(p, string(p), handler) +} + +// SetHTTPHandlerAtPath sets the HTTP handler for a given protocol using the +// given path. Automatically manages the well-known resource mapping. +// http.StripPrefix is called on the handler, so the handler will be unaware of +// its prefix path. +func (h *Host) SetHTTPHandlerAtPath(p protocol.ID, path string, handler http.Handler) { + if path == "" || path[len(path)-1] != '/' { + // We are nesting this handler under this path, so it should end with a slash. + path += "/" + } + h.WellKnownHandler.AddProtocolMeta(p, ProtocolMeta{Path: path}) + h.serveMuxInit() + // Do not trim the trailing / from path + // This allows us to serve `/a/b` when we mount a handler for `/b` at path `/a` + h.ServeMux.Handle(path, http.StripPrefix(strings.TrimSuffix(path, "/"), handler)) +} + +// PeerMetadataGetter lets RoundTrippers implement a specific way of caching a peer's protocol mapping. +type PeerMetadataGetter interface { + GetPeerMetadata() (PeerMeta, error) +} + +type streamRoundTripper struct { + server peer.ID + addrsAdded sync.Once + serverAddrs []ma.Multiaddr + h host.Host + httpHost *Host +} + +// streamReadCloser wraps an io.ReadCloser and closes the underlying stream when +// closed (as well as closing the wrapped ReadCloser). This is necessary because +// we have two things to close, the body and the stream. The stream isn't closed +// by the body automatically, as hinted at by the fact that `http.ReadResponse` +// takes a bufio.Reader. +type streamReadCloser struct { + io.ReadCloser + s network.Stream +} + +func (s *streamReadCloser) Close() error { + s.s.Close() + return s.ReadCloser.Close() +} + +func (rt *streamRoundTripper) GetPeerMetadata() (PeerMeta, error) { + ctx := context.Background() + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(WellKnownRequestTimeout)) + defer cancel() + return rt.httpHost.getAndStorePeerMetadata(ctx, rt, rt.server) +} + +// RoundTrip implements http.RoundTripper. +func (rt *streamRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + // Add the addresses we learned about for this server + rt.addrsAdded.Do(func() { + if len(rt.serverAddrs) > 0 { + rt.h.Peerstore().AddAddrs(rt.server, rt.serverAddrs, peerstore.TempAddrTTL) + } + rt.serverAddrs = nil // may as well cleanup + }) + + s, err := rt.h.NewStream(r.Context(), rt.server, ProtocolIDForMultistreamSelect) + if err != nil { + return nil, err + } + + // Write connection: close header to ensure the stream is closed after the response + r.Header.Add("connection", "close") + + go func() { + defer s.CloseWrite() + r.Write(s) + if r.Body != nil { + r.Body.Close() + } + }() + + if deadline, ok := r.Context().Deadline(); ok { + s.SetReadDeadline(deadline) + } + + resp, err := http.ReadResponse(bufio.NewReader(s), r) + if err != nil { + s.Close() + return nil, err + } + resp.Body = &streamReadCloser{resp.Body, s} + + return resp, nil +} + +// roundTripperForSpecificServer is an http.RoundTripper targets a specific server. Still reuses the underlying RoundTripper for the requests. +// The underlying RoundTripper MUST be an HTTP Transport. +type roundTripperForSpecificServer struct { + http.RoundTripper + ownRoundtripper bool + httpHost *Host + server peer.ID + targetServerAddr string + sni string + scheme string + cachedProtos PeerMeta +} + +func (rt *roundTripperForSpecificServer) GetPeerMetadata() (PeerMeta, error) { + // Do we already have the peer's protocol mapping? + if rt.cachedProtos != nil { + return rt.cachedProtos, nil + } + + // if the underlying roundtripper implements GetPeerMetadata, use that + if g, ok := rt.RoundTripper.(PeerMetadataGetter); ok { + wk, err := g.GetPeerMetadata() + if err == nil { + rt.cachedProtos = wk + return wk, nil + } + } + + ctx := context.Background() + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(WellKnownRequestTimeout)) + defer cancel() + wk, err := rt.httpHost.getAndStorePeerMetadata(ctx, rt, rt.server) + if err == nil { + rt.cachedProtos = wk + return wk, nil + } + return wk, err +} + +// RoundTrip implements http.RoundTripper. +func (rt *roundTripperForSpecificServer) RoundTrip(r *http.Request) (*http.Response, error) { + if (r.URL.Scheme != "" && r.URL.Scheme != rt.scheme) || (r.URL.Host != "" && r.URL.Host != rt.targetServerAddr) { + return nil, fmt.Errorf("this transport is only for requests to %s://%s", rt.scheme, rt.targetServerAddr) + } + r.URL.Scheme = rt.scheme + r.URL.Host = rt.targetServerAddr + r.Host = rt.sni + return rt.RoundTripper.RoundTrip(r) +} + +func (rt *roundTripperForSpecificServer) CloseIdleConnections() { + if rt.ownRoundtripper { + // Safe to close idle connections, since we own the RoundTripper. We + // aren't closing other's idle connections. + type closeIdler interface { + CloseIdleConnections() + } + if tr, ok := rt.RoundTripper.(closeIdler); ok { + tr.CloseIdleConnections() + } + } + // No-op, since we don't want users thinking they are closing idle + // connections for this server, when in fact they are closing all idle + // connections +} + +// namespacedRoundTripper is a round tripper that prefixes all requests with a +// given path prefix. It is used to namespace requests to a specific protocol. +type namespacedRoundTripper struct { + http.RoundTripper + protocolPrefix string + protocolPrefixRaw string +} + +func (rt *namespacedRoundTripper) GetPeerMetadata() (PeerMeta, error) { + if g, ok := rt.RoundTripper.(PeerMetadataGetter); ok { + return g.GetPeerMetadata() + } + + return nil, fmt.Errorf("can not get peer protocol map. Inner roundtripper does not implement GetPeerMetadata") +} + +// RoundTrip implements http.RoundTripper. +func (rt *namespacedRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + if !strings.HasPrefix(r.URL.Path, rt.protocolPrefix) { + r.URL.Path = rt.protocolPrefix + r.URL.Path + } + if !strings.HasPrefix(r.URL.RawPath, rt.protocolPrefixRaw) { + r.URL.RawPath = rt.protocolPrefixRaw + r.URL.Path + } + + return rt.RoundTripper.RoundTrip(r) +} + +// NamespaceRoundTripper returns an http.RoundTripper that are scoped to the given protocol on the given server. +func (h *Host) NamespaceRoundTripper(roundtripper http.RoundTripper, p protocol.ID, server peer.ID) (*namespacedRoundTripper, error) { + ctx := context.Background() + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(WellKnownRequestTimeout)) + defer cancel() + protos, err := h.getAndStorePeerMetadata(ctx, roundtripper, server) + if err != nil { + return &namespacedRoundTripper{}, err + } + + v, ok := protos[p] + if !ok { + return &namespacedRoundTripper{}, fmt.Errorf("no protocol %s for server %s", p, server) + } + + path := v.Path + if path[len(path)-1] == '/' { + // Trim the trailing slash, since it's common to make requests starting with a leading forward slash for the path + path = path[:len(path)-1] + } + + u, err := url.Parse(path) + if err != nil { + return &namespacedRoundTripper{}, fmt.Errorf("invalid path %s for protocol %s for server %s", v.Path, p, server) + } + + return &namespacedRoundTripper{ + RoundTripper: roundtripper, + protocolPrefix: u.Path, + protocolPrefixRaw: u.RawPath, + }, nil +} + +// NamespacedClient returns an http.Client that is scoped to the given protocol +// on the given server. It creates a new RoundTripper for each call. If you are +// creating many namespaced clients, consider creating a round tripper directly +// and namespacing the roundripper yourself, then creating clients from the +// namespace round tripper. +func (h *Host) NamespacedClient(p protocol.ID, server peer.AddrInfo, opts ...RoundTripperOption) (http.Client, error) { + rt, err := h.NewConstrainedRoundTripper(server, opts...) + if err != nil { + return http.Client{}, err + } + + nrt, err := h.NamespaceRoundTripper(rt, p, server.ID) + if err != nil { + return http.Client{}, err + } + + return http.Client{Transport: nrt}, nil +} + +// NewConstrainedRoundTripper returns an http.RoundTripper that can fulfill and HTTP +// request to the given server. It may use an HTTP transport or a stream based +// transport. It is valid to pass an empty server.ID. +// If there are multiple addresses for the server, it will pick the best +// transport (stream vs standard HTTP) using the following rules: +// - If PreferHTTPTransport is set, use the HTTP transport. +// - If ServerMustAuthenticatePeerID is set, use the stream transport, as the +// HTTP transport does not do peer id auth yet. +// - If we already have a connection on a stream transport, use that. +// - Otherwise, if we have both, use the HTTP transport. +func (h *Host) NewConstrainedRoundTripper(server peer.AddrInfo, opts ...RoundTripperOption) (http.RoundTripper, error) { + options := roundTripperOpts{} + for _, o := range opts { + options = o(options) + } + + if options.serverMustAuthenticatePeerID && server.ID == "" { + return nil, fmt.Errorf("server must authenticate peer ID, but no peer ID provided") + } + + httpAddrs := make([]ma.Multiaddr, 0, 1) // The common case of a single http address + nonHTTPAddrs := make([]ma.Multiaddr, 0, len(server.Addrs)) + + firstAddrIsHTTP := false + + for i, addr := range server.Addrs { + addr, isHTTP := normalizeHTTPMultiaddr(addr) + if isHTTP { + if i == 0 { + firstAddrIsHTTP = true + } + httpAddrs = append(httpAddrs, addr) + } else { + nonHTTPAddrs = append(nonHTTPAddrs, addr) + } + } + + // Do we have an existing connection to this peer? + existingStreamConn := false + if server.ID != "" && h.StreamHost != nil { + existingStreamConn = len(h.StreamHost.Network().ConnsToPeer(server.ID)) > 0 + } + + // Currently the HTTP transport can not authenticate peer IDs. + if !options.serverMustAuthenticatePeerID && len(httpAddrs) > 0 && (options.preferHTTPTransport || (firstAddrIsHTTP && !existingStreamConn)) { + parsed := parseMultiaddr(httpAddrs[0]) + scheme := "http" + if parsed.useHTTPS { + scheme = "https" + } + + h.createDefaultClientRoundTripper.Do(func() { + if h.DefaultClientRoundTripper == nil { + h.DefaultClientRoundTripper = &http.Transport{} + } + }) + rt := h.DefaultClientRoundTripper + ownRoundtripper := false + if parsed.sni != parsed.host { + // We have a different host and SNI (e.g. using an IP address but specifying a SNI) + // We need to make our own transport to support this. + rt = rt.Clone() + rt.TLSClientConfig.ServerName = parsed.sni + ownRoundtripper = true + } + + return &roundTripperForSpecificServer{ + RoundTripper: rt, + ownRoundtripper: ownRoundtripper, + httpHost: h, + server: server.ID, + targetServerAddr: parsed.host + ":" + parsed.port, + sni: parsed.sni, + scheme: scheme, + }, nil + } + + // Otherwise use a stream based transport + if h.StreamHost == nil { + return nil, fmt.Errorf("can not use the HTTP transport (either no address or PeerID auth is required), and no stream host provided") + } + if !existingStreamConn { + if server.ID == "" { + return nil, fmt.Errorf("can not use the HTTP transport, and no server peer ID provided") + } + } + + return &streamRoundTripper{h: h.StreamHost, server: server.ID, serverAddrs: nonHTTPAddrs, httpHost: h}, nil +} + +type httpMultiaddr struct { + useHTTPS bool + host string + port string + sni string +} + +func parseMultiaddr(addr ma.Multiaddr) httpMultiaddr { + out := httpMultiaddr{} + ma.ForEach(addr, func(c ma.Component) bool { + switch c.Protocol().Code { + case ma.P_IP4, ma.P_IP6, ma.P_DNS, ma.P_DNS4, ma.P_DNS6: + out.host = c.Value() + case ma.P_TCP, ma.P_UDP: + out.port = c.Value() + case ma.P_TLS, ma.P_HTTPS: + out.useHTTPS = true + case ma.P_SNI: + out.sni = c.Value() + + } + return out.host == "" || out.port == "" || !out.useHTTPS || out.sni == "" + }) + + if out.useHTTPS && out.sni == "" { + out.sni = out.host + } + return out +} + +var httpComponent, _ = ma.NewComponent("http", "") +var tlsComponent, _ = ma.NewComponent("tls", "") + +// normalizeHTTPMultiaddr converts an https multiaddr to a tls/http one. +// Returns a bool indicating if the input multiaddr has an http (or https) component. +func normalizeHTTPMultiaddr(addr ma.Multiaddr) (ma.Multiaddr, bool) { + isHTTPMultiaddr := false + beforeHTTPS, afterIncludingHTTPS := ma.SplitFunc(addr, func(c ma.Component) bool { + if c.Protocol().Code == ma.P_HTTP { + isHTTPMultiaddr = true + } + + if c.Protocol().Code == ma.P_HTTPS { + isHTTPMultiaddr = true + return true + } + return false + }) + + if afterIncludingHTTPS == nil { + // No HTTPS component, just return the original + return addr, isHTTPMultiaddr + } + + _, afterHTTPS := ma.SplitFirst(afterIncludingHTTPS) + if afterHTTPS == nil { + return ma.Join(beforeHTTPS, tlsComponent, httpComponent), isHTTPMultiaddr + } + + return ma.Join(beforeHTTPS, tlsComponent, httpComponent, afterHTTPS), isHTTPMultiaddr +} + +// getAndStorePeerMetadata looks up the protocol path in the well-known mapping and +// returns it. Will only store the peer's protocol mapping if the server ID is +// provided. +func (h *Host) getAndStorePeerMetadata(ctx context.Context, roundtripper http.RoundTripper, server peer.ID) (PeerMeta, error) { + if h.peerMetadata == nil { + h.peerMetadata = newPeerMetadataCache() + } + if meta, ok := h.peerMetadata.Get(server); server != "" && ok { + return meta, nil + } + + var meta PeerMeta + var err error + if h.EnableCompatibilityWithLegacyWellKnownEndpoint { + type metaAndErr struct { + m PeerMeta + err error + } + legacyRespCh := make(chan metaAndErr, 1) + wellKnownRespCh := make(chan metaAndErr, 1) + ctx, cancel := context.WithCancel(ctx) + go func() { + meta, err := requestPeerMeta(ctx, roundtripper, LegacyWellKnownProtocols) + legacyRespCh <- metaAndErr{meta, err} + }() + go func() { + meta, err := requestPeerMeta(ctx, roundtripper, WellKnownProtocols) + wellKnownRespCh <- metaAndErr{meta, err} + }() + select { + case resp := <-legacyRespCh: + if resp.err != nil { + resp = <-wellKnownRespCh + } + meta, err = resp.m, resp.err + case resp := <-wellKnownRespCh: + if resp.err != nil { + legacyResp := <-legacyRespCh + if legacyResp.err != nil { + // If both endpoints error, return the error from the well + // known resource (not the legacy well known resource) + meta, err = resp.m, resp.err + } else { + meta, err = legacyResp.m, legacyResp.err + } + } else { + meta, err = resp.m, resp.err + } + } + cancel() + } else { + meta, err = requestPeerMeta(ctx, roundtripper, WellKnownProtocols) + } + if err != nil { + return nil, err + } + + if server != "" { + h.peerMetadata.Add(server, meta) + } + + return meta, nil +} + +func requestPeerMeta(ctx context.Context, roundtripper http.RoundTripper, wellKnownResource string) (PeerMeta, error) { + req, err := http.NewRequest("GET", wellKnownResource, nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", "application/json") + + client := http.Client{Transport: roundtripper} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + meta := PeerMeta{} + err = json.NewDecoder(&io.LimitedReader{ + R: resp.Body, + N: peerMetadataLimit, + }).Decode(&meta) + if err != nil { + return nil, err + } + + return meta, nil +} + +// SetPeerMetadata adds a peer's protocol metadata to the http host. Useful if +// you have out-of-band knowledge of a peer's protocol mapping. +func (h *Host) SetPeerMetadata(server peer.ID, meta PeerMeta) { + if h.peerMetadata == nil { + h.peerMetadata = newPeerMetadataCache() + } + h.peerMetadata.Add(server, meta) +} + +// AddPeerMetadata merges the given peer's protocol metadata to the http host. Useful if +// you have out-of-band knowledge of a peer's protocol mapping. +func (h *Host) AddPeerMetadata(server peer.ID, meta PeerMeta) { + if h.peerMetadata == nil { + h.peerMetadata = newPeerMetadataCache() + } + origMeta, ok := h.peerMetadata.Get(server) + if !ok { + h.peerMetadata.Add(server, meta) + return + } + for proto, m := range meta { + origMeta[proto] = m + } + h.peerMetadata.Add(server, origMeta) +} + +// GetPeerMetadata gets a peer's cached protocol metadata from the http host. +func (h *Host) GetPeerMetadata(server peer.ID) (PeerMeta, bool) { + if h.peerMetadata == nil { + return nil, false + } + return h.peerMetadata.Get(server) +} + +// RemovePeerMetadata removes a peer's protocol metadata from the http host +func (h *Host) RemovePeerMetadata(server peer.ID) { + if h.peerMetadata == nil { + return + } + h.peerMetadata.Remove(server) +} + +func connectionCloseHeaderMiddleware(next http.Handler) http.Handler { + // Sets connection: close. It's preferable to not reuse streams for HTTP. + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Connection", "close") + next.ServeHTTP(w, r) + }) +} diff --git a/go-libp2p/p2p/http/libp2phttp_test.go b/go-libp2p/p2p/http/libp2phttp_test.go new file mode 100644 index 0000000..a444c6e --- /dev/null +++ b/go-libp2p/p2p/http/libp2phttp_test.go @@ -0,0 +1,721 @@ +package libp2phttp_test + +import ( + "bytes" + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "fmt" + "io" + "math/big" + "net" + "net/http" + "net/netip" + "net/url" + "os" + "reflect" + "strings" + "testing" + "time" + + "github.com/libp2p/go-libp2p" + host "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + libp2phttp "github.com/libp2p/go-libp2p/p2p/http" + httpping "github.com/libp2p/go-libp2p/p2p/http/ping" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestHTTPOverStreams(t *testing.T) { + serverHost, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + ) + require.NoError(t, err) + + httpHost := libp2phttp.Host{StreamHost: serverHost} + + httpHost.SetHTTPHandler("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello")) + })) + + // Start server + go httpHost.Serve() + defer httpHost.Close() + + // Start client + clientHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + clientHost.Connect(context.Background(), peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverHost.Addrs(), + }) + + clientRT, err := (&libp2phttp.Host{StreamHost: clientHost}).NewConstrainedRoundTripper(peer.AddrInfo{ID: serverHost.ID()}) + require.NoError(t, err) + + client := &http.Client{Transport: clientRT} + + resp, err := client.Get("/hello") + require.NoError(t, err) + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + require.Equal(t, "hello", string(body)) +} + +func TestHTTPOverStreamsSendsConnectionClose(t *testing.T) { + serverHost, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + ) + require.NoError(t, err) + + httpHost := libp2phttp.Host{StreamHost: serverHost} + + connectionHeaderVal := make(chan string, 1) + httpHost.SetHTTPHandlerAtPath("/hello", "/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello")) + connectionHeaderVal <- r.Header.Get("Connection") + })) + + // Start server + go httpHost.Serve() + defer httpHost.Close() + + // run client + clientHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + clientHost.Connect(context.Background(), peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverHost.Addrs(), + }) + clientHttpHost := libp2phttp.Host{StreamHost: clientHost} + rt, err := clientHttpHost.NewConstrainedRoundTripper(peer.AddrInfo{ID: serverHost.ID()}) + require.NoError(t, err) + client := &http.Client{Transport: rt} + _, err = client.Get("/") + require.NoError(t, err) + + select { + case val := <-connectionHeaderVal: + require.Equal(t, "close", strings.ToLower(val)) + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for connection header") + } +} + +func TestHTTPOverStreamsContextAndClientTimeout(t *testing.T) { + const clientTimeout = 200 * time.Millisecond + + serverHost, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + ) + require.NoError(t, err) + + httpHost := libp2phttp.Host{StreamHost: serverHost} + httpHost.SetHTTPHandler("/hello/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(2 * clientTimeout) + w.Write([]byte("hello")) + })) + + // Start server + go httpHost.Serve() + defer httpHost.Close() + + // Start client + clientHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + clientHost.Connect(context.Background(), peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverHost.Addrs(), + }) + + clientRT, err := (&libp2phttp.Host{StreamHost: clientHost}).NewConstrainedRoundTripper(peer.AddrInfo{ID: serverHost.ID()}) + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), clientTimeout) + defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/hello/", nil) + require.NoError(t, err) + + client := &http.Client{Transport: clientRT} + _, err = client.Do(req) + require.Error(t, err) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + t.Log("OK, deadline exceeded waiting for response as expected") + + // Make another request, this time using http.Client.Timeout. + clientRT, err = (&libp2phttp.Host{StreamHost: clientHost}).NewConstrainedRoundTripper(peer.AddrInfo{ID: serverHost.ID()}) + require.NoError(t, err) + + client = &http.Client{ + Transport: clientRT, + Timeout: clientTimeout, + } + + _, err = client.Get("/hello/") + require.Error(t, err) + var uerr *url.Error + require.ErrorAs(t, err, &uerr) + require.True(t, uerr.Timeout()) + t.Log("OK, timed out waiting for response as expected") +} + +func TestHTTPOverStreamsReturnsConnectionClose(t *testing.T) { + serverHost, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + ) + require.NoError(t, err) + + httpHost := libp2phttp.Host{StreamHost: serverHost} + + httpHost.SetHTTPHandlerAtPath("/hello", "/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello")) + })) + + // Start server + go httpHost.Serve() + defer httpHost.Close() + + // Start client + clientHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + clientHost.Connect(context.Background(), peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverHost.Addrs(), + }) + + s, err := clientHost.NewStream(context.Background(), serverHost.ID(), libp2phttp.ProtocolIDForMultistreamSelect) + require.NoError(t, err) + _, err = s.Write([]byte("GET / HTTP/1.1\r\nHost: \r\n\r\n")) + require.NoError(t, err) + + out := make([]byte, 1024) + n, err := s.Read(out) + if err != io.EOF { + require.NoError(t, err) + } + + require.Contains(t, strings.ToLower(string(out[:n])), "connection: close") +} + +func TestRoundTrippers(t *testing.T) { + serverHost, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + ) + require.NoError(t, err) + + httpHost := libp2phttp.Host{ + InsecureAllowHTTP: true, + StreamHost: serverHost, + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + + httpHost.SetHTTPHandler("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("hello")) + })) + + // Start stream based server + go httpHost.Serve() + defer httpHost.Close() + + serverMultiaddrs := httpHost.Addrs() + serverHTTPAddr := serverMultiaddrs[1] + + testCases := []struct { + name string + setupRoundTripper func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper + expectStreamRoundTripper bool + }{ + { + name: "HTTP preferred", + setupRoundTripper: func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper { + rt, err := clientHTTPHost.NewConstrainedRoundTripper(peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverMultiaddrs, + }, libp2phttp.PreferHTTPTransport) + require.NoError(t, err) + return rt + }, + }, + { + name: "HTTP first", + setupRoundTripper: func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper { + rt, err := clientHTTPHost.NewConstrainedRoundTripper(peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: []ma.Multiaddr{serverHTTPAddr, serverHost.Addrs()[0]}, + }) + require.NoError(t, err) + return rt + }, + }, + { + name: "No HTTP transport", + setupRoundTripper: func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper { + rt, err := clientHTTPHost.NewConstrainedRoundTripper(peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: []ma.Multiaddr{serverHost.Addrs()[0]}, + }) + require.NoError(t, err) + return rt + }, + expectStreamRoundTripper: true, + }, + { + name: "Stream transport first", + setupRoundTripper: func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper { + rt, err := clientHTTPHost.NewConstrainedRoundTripper(peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: []ma.Multiaddr{serverHost.Addrs()[0], serverHTTPAddr}, + }) + require.NoError(t, err) + return rt + }, + expectStreamRoundTripper: true, + }, + { + name: "Existing stream transport connection", + setupRoundTripper: func(t *testing.T, clientStreamHost host.Host, clientHTTPHost *libp2phttp.Host) http.RoundTripper { + clientStreamHost.Connect(context.Background(), peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: serverHost.Addrs(), + }) + rt, err := clientHTTPHost.NewConstrainedRoundTripper(peer.AddrInfo{ + ID: serverHost.ID(), + Addrs: []ma.Multiaddr{serverHTTPAddr, serverHost.Addrs()[0]}, + }) + require.NoError(t, err) + return rt + }, + expectStreamRoundTripper: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Start client + clientStreamHost, err := libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + defer clientStreamHost.Close() + + clientHttpHost := &libp2phttp.Host{StreamHost: clientStreamHost} + + rt := tc.setupRoundTripper(t, clientStreamHost, clientHttpHost) + if tc.expectStreamRoundTripper { + // Hack to get the private type of this roundtripper + typ := reflect.TypeOf(rt).String() + require.Contains(t, typ, "streamRoundTripper", "Expected stream based round tripper") + } + + for _, tc := range []bool{true, false} { + name := "" + if tc { + name = "with namespaced roundtripper" + } + t.Run(name, func(t *testing.T) { + var resp *http.Response + var err error + if tc { + var h libp2phttp.Host + require.NoError(t, err) + nrt, err := h.NamespaceRoundTripper(rt, "/hello", serverHost.ID()) + require.NoError(t, err) + client := &http.Client{Transport: nrt} + resp, err = client.Get("/") + require.NoError(t, err) + } else { + client := &http.Client{Transport: rt} + resp, err = client.Get("/hello/") + require.NoError(t, err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, "hello", string(body)) + }) + } + + // Read the well-known resource + wk, err := rt.(libp2phttp.PeerMetadataGetter).GetPeerMetadata() + require.NoError(t, err) + + expectedMap := make(libp2phttp.PeerMeta) + expectedMap["/hello"] = libp2phttp.ProtocolMeta{Path: "/hello/"} + require.Equal(t, expectedMap, wk) + }) + } +} + +func TestPlainOldHTTPServer(t *testing.T) { + mux := http.NewServeMux() + wk := libp2phttp.WellKnownHandler{} + mux.Handle(libp2phttp.WellKnownProtocols, &wk) + + mux.Handle("/ping/", httpping.Ping{}) + wk.AddProtocolMeta(httpping.PingProtocolID, libp2phttp.ProtocolMeta{Path: "/ping/"}) + + server := &http.Server{Addr: "127.0.0.1:0", Handler: mux} + + l, err := net.Listen("tcp", server.Addr) + require.NoError(t, err) + + go server.Serve(l) + defer server.Close() + + // That's all for the server, now the client: + + serverAddrParts := strings.Split(l.Addr().String(), ":") + + testCases := []struct { + name string + do func(*testing.T, *http.Request) (*http.Response, error) + getWellKnown func(*testing.T) (libp2phttp.PeerMeta, error) + }{ + { + name: "using libp2phttp", + do: func(t *testing.T, request *http.Request) (*http.Response, error) { + var clientHttpHost libp2phttp.Host + rt, err := clientHttpHost.NewConstrainedRoundTripper(peer.AddrInfo{Addrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/" + serverAddrParts[1] + "/http")}}) + require.NoError(t, err) + + client := &http.Client{Transport: rt} + return client.Do(request) + }, + getWellKnown: func(t *testing.T) (libp2phttp.PeerMeta, error) { + var clientHttpHost libp2phttp.Host + rt, err := clientHttpHost.NewConstrainedRoundTripper(peer.AddrInfo{Addrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/" + serverAddrParts[1] + "/http")}}) + require.NoError(t, err) + return rt.(libp2phttp.PeerMetadataGetter).GetPeerMetadata() + }, + }, + { + name: "using stock http client", + do: func(t *testing.T, request *http.Request) (*http.Response, error) { + request.URL.Scheme = "http" + request.URL.Host = l.Addr().String() + request.Host = l.Addr().String() + + client := http.Client{} + return client.Do(request) + }, + getWellKnown: func(t *testing.T) (libp2phttp.PeerMeta, error) { + client := http.Client{} + resp, err := client.Get("http://" + l.Addr().String() + libp2phttp.WellKnownProtocols) + require.NoError(t, err) + + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + var out libp2phttp.PeerMeta + err = json.Unmarshal(b, &out) + return out, err + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + body := [32]byte{} + _, err = rand.Reader.Read(body[:]) + require.NoError(t, err) + req, err := http.NewRequest(http.MethodPost, "/ping/", bytes.NewReader(body[:])) + require.NoError(t, err) + resp, err := tc.do(t, req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + rBody := [32]byte{} + _, err = io.ReadFull(resp.Body, rBody[:]) + require.NoError(t, err) + require.Equal(t, body, rBody) + + // Make sure we can get the well known resource + protoMap, err := tc.getWellKnown(t) + require.NoError(t, err) + + expectedMap := make(libp2phttp.PeerMeta) + expectedMap[httpping.PingProtocolID] = libp2phttp.ProtocolMeta{Path: "/ping/"} + require.Equal(t, expectedMap, protoMap) + }) + } +} + +func TestHostZeroValue(t *testing.T) { + server := libp2phttp.Host{ + InsecureAllowHTTP: true, + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + } + server.SetHTTPHandler("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello")) })) + go func() { + server.Serve() + }() + defer server.Close() + + c := libp2phttp.Host{} + client, err := c.NamespacedClient("/hello", peer.AddrInfo{Addrs: server.Addrs()}) + require.NoError(t, err) + resp, err := client.Get("/") + require.NoError(t, err) + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + require.Equal(t, "hello", string(body), "expected response from server") +} + +func TestHTTPS(t *testing.T) { + server := libp2phttp.Host{ + TLSConfig: selfSignedTLSConfig(t), + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/https")}, + } + server.SetHTTPHandler(httpping.PingProtocolID, httpping.Ping{}) + go func() { + server.Serve() + }() + defer server.Close() + + clientTransport := http.DefaultTransport.(*http.Transport).Clone() + clientTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + client := libp2phttp.Host{ + DefaultClientRoundTripper: clientTransport, + } + httpClient, err := client.NamespacedClient(httpping.PingProtocolID, peer.AddrInfo{Addrs: server.Addrs()}) + require.NoError(t, err) + err = httpping.SendPing(httpClient) + require.NoError(t, err) +} + +func selfSignedTLSConfig(t *testing.T) *tls.Config { + t.Helper() + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + notBefore := time.Now() + notAfter := notBefore.Add(365 * 24 * time.Hour) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + require.NoError(t, err) + + certTemplate := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Test"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &priv.PublicKey, priv) + require.NoError(t, err) + + cert := tls.Certificate{ + Certificate: [][]byte{derBytes}, + PrivateKey: priv, + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + return tlsConfig +} + +func TestCustomServeMux(t *testing.T) { + serveMux := http.NewServeMux() + serveMux.Handle("/ping/", httpping.Ping{}) + + server := libp2phttp.Host{ + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + ServeMux: serveMux, + InsecureAllowHTTP: true, + } + server.WellKnownHandler.AddProtocolMeta(httpping.PingProtocolID, libp2phttp.ProtocolMeta{Path: "/ping/"}) + go func() { + server.Serve() + }() + defer server.Close() + + addrs := server.Addrs() + require.Len(t, addrs, 1) + var clientHttpHost libp2phttp.Host + rt, err := clientHttpHost.NewConstrainedRoundTripper(peer.AddrInfo{Addrs: addrs}, libp2phttp.PreferHTTPTransport) + require.NoError(t, err) + + client := &http.Client{Transport: rt} + body := [32]byte{} + req, _ := http.NewRequest(http.MethodPost, "/ping/", bytes.NewReader(body[:])) + resp, err := client.Do(req) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode) +} + +func TestSetHandlerAtPath(t *testing.T) { + hf := func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + } + tests := []struct { + prefix, rest string + paths200 []string + paths404 []string + }{ + { + prefix: "/", + rest: "/", + paths200: []string{"/", "/a/", "/b", "/a/b"}, + }, + { + prefix: "/a", + rest: "/b/", + paths200: []string{"/a/b/", "///a///b/", "/a/b/c"}, + // Not being able to serve /a/b when handling /a/b/ is a rather annoying limitation + // of http.StripPrefix mechanism. This happens because /a/b is redirected to /b/ + // as the prefix /a is stripped when the redirect happens + paths404: []string{"/a/b", "/a", "/b", "/a/a"}, + }, + { + prefix: "/", + rest: "/b/", + paths200: []string{"/b", "/b/c", "/b/c/"}, + paths404: []string{"/", "/a/b"}, + }, + } + for i, tc := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + nestedMx := http.NewServeMux() + nestedMx.HandleFunc(tc.rest, hf) + server := libp2phttp.Host{ + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + InsecureAllowHTTP: true, + } + server.SetHTTPHandlerAtPath("test", tc.prefix, nestedMx) + go func() { + server.Serve() + }() + defer server.Close() + addrs := server.Addrs() + require.Len(t, addrs, 1) + port, err := addrs[0].ValueForProtocol(ma.P_TCP) + require.NoError(t, err) + httpAddr := fmt.Sprintf("http://127.0.0.1:%s", port) + for _, p := range tc.paths200 { + resp, err := http.Get(httpAddr + p) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode, "path:%s", p) + resp.Body.Close() + } + for _, p := range tc.paths404 { + resp, _ := http.Get(httpAddr + p) + require.Equal(t, 404, resp.StatusCode, "path:%s", p) + resp.Body.Close() + } + }) + } +} + +func TestServerLegacyWellKnownResource(t *testing.T) { + mkHTTPServer := func(wellKnown string) ma.Multiaddr { + mux := http.NewServeMux() + wk := libp2phttp.WellKnownHandler{} + mux.Handle(wellKnown, &wk) + + mux.Handle("/ping/", httpping.Ping{}) + wk.AddProtocolMeta(httpping.PingProtocolID, libp2phttp.ProtocolMeta{Path: "/ping/"}) + + server := &http.Server{Addr: "127.0.0.1:0", Handler: mux} + + l, err := net.Listen("tcp", server.Addr) + require.NoError(t, err) + + go server.Serve(l) + t.Cleanup(func() { server.Close() }) + addrPort, err := netip.ParseAddrPort(l.Addr().String()) + require.NoError(t, err) + return ma.StringCast(fmt.Sprintf("/ip4/%s/tcp/%d/http", addrPort.Addr().String(), addrPort.Port())) + } + + mkServerlibp2phttp := func(enableLegacyWellKnown bool) ma.Multiaddr { + server := libp2phttp.Host{ + EnableCompatibilityWithLegacyWellKnownEndpoint: enableLegacyWellKnown, + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")}, + InsecureAllowHTTP: true, + } + server.SetHTTPHandler(httpping.PingProtocolID, httpping.Ping{}) + go server.Serve() + t.Cleanup(func() { server.Close() }) + return server.Addrs()[0] + } + + type testCase struct { + name string + client libp2phttp.Host + serverAddr ma.Multiaddr + expectErr bool + } + + var testCases = []testCase{ + { + name: "legacy server, client with compat", + client: libp2phttp.Host{EnableCompatibilityWithLegacyWellKnownEndpoint: true}, + serverAddr: mkHTTPServer(libp2phttp.LegacyWellKnownProtocols), + }, + { + name: "up-to-date http server, client with compat", + client: libp2phttp.Host{EnableCompatibilityWithLegacyWellKnownEndpoint: true}, + serverAddr: mkHTTPServer(libp2phttp.WellKnownProtocols), + }, + { + name: "up-to-date http server, client without compat", + client: libp2phttp.Host{}, + serverAddr: mkHTTPServer(libp2phttp.WellKnownProtocols), + }, + { + name: "libp2phttp server with compat, client with compat", + client: libp2phttp.Host{EnableCompatibilityWithLegacyWellKnownEndpoint: true}, + serverAddr: mkServerlibp2phttp(true), + }, + { + name: "libp2phttp server without compat, client with compat", + client: libp2phttp.Host{EnableCompatibilityWithLegacyWellKnownEndpoint: true}, + serverAddr: mkServerlibp2phttp(false), + }, + { + name: "libp2phttp server with compat, client without compat", + client: libp2phttp.Host{}, + serverAddr: mkServerlibp2phttp(true), + }, + { + name: "legacy server, client without compat", + client: libp2phttp.Host{}, + serverAddr: mkHTTPServer(libp2phttp.LegacyWellKnownProtocols), + expectErr: true, + }, + } + + for i := range testCases { + tc := &testCases[i] // to not copy the lock in libp2phttp.Host + t.Run(tc.name, func(t *testing.T) { + if tc.expectErr { + _, err := tc.client.NamespacedClient(httpping.PingProtocolID, peer.AddrInfo{Addrs: []ma.Multiaddr{tc.serverAddr}}) + require.Error(t, err) + return + } + httpClient, err := tc.client.NamespacedClient(httpping.PingProtocolID, peer.AddrInfo{Addrs: []ma.Multiaddr{tc.serverAddr}}) + require.NoError(t, err) + + err = httpping.SendPing(httpClient) + require.NoError(t, err) + }) + } + +} diff --git a/go-libp2p/p2p/http/options.go b/go-libp2p/p2p/http/options.go new file mode 100644 index 0000000..0062e59 --- /dev/null +++ b/go-libp2p/p2p/http/options.go @@ -0,0 +1,24 @@ +package libp2phttp + +type RoundTripperOption func(o roundTripperOpts) roundTripperOpts + +type roundTripperOpts struct { + preferHTTPTransport bool + serverMustAuthenticatePeerID bool +} + +// PreferHTTPTransport tells the roundtripper constructor to prefer using an +// HTTP transport (as opposed to a libp2p stream transport). Useful, for +// example, if you want to attempt to leverage HTTP caching. +func PreferHTTPTransport(o roundTripperOpts) roundTripperOpts { + o.preferHTTPTransport = true + return o +} + +// ServerMustAuthenticatePeerID tells the roundtripper constructor that we MUST +// authenticate the Server's PeerID. Note: this currently means we can not use a +// native HTTP transport (HTTP peer id authentication is not yet implemented: https://github.com/libp2p/specs/pull/564). +func ServerMustAuthenticatePeerID(o roundTripperOpts) roundTripperOpts { + o.serverMustAuthenticatePeerID = true + return o +} diff --git a/go-libp2p/p2p/http/ping/ping.go b/go-libp2p/p2p/http/ping/ping.go new file mode 100644 index 0000000..2c2ad80 --- /dev/null +++ b/go-libp2p/p2p/http/ping/ping.go @@ -0,0 +1,67 @@ +package httpping + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "io" + "net/http" + "strconv" +) + +const pingSize = 32 +const PingProtocolID = "/http-ping/1" + +type Ping struct{} + +var _ http.Handler = Ping{} + +// ServeHTTP implements http.Handler. +func (Ping) ServeHTTP(w http.ResponseWriter, r *http.Request) { + body := [pingSize]byte{} + _, err := io.ReadFull(r.Body, body[:]) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", strconv.Itoa(pingSize)) + w.Write(body[:]) +} + +// SendPing send an ping request over HTTP. The provided client should be namespaced to the Ping protocol. +func SendPing(client http.Client) error { + body := [pingSize]byte{} + _, err := io.ReadFull(rand.Reader, body[:]) + if err != nil { + return err + } + req, err := http.NewRequest("POST", "/", bytes.NewReader(body[:])) + req.Header.Set("Content-Type", "application/octet-stream") + req.Header.Set("Content-Length", strconv.Itoa(pingSize)) + if err != nil { + return err + } + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + rBody := [pingSize]byte{} + _, err = io.ReadFull(resp.Body, rBody[:]) + if err != nil { + return err + } + + if !bytes.Equal(body[:], rBody[:]) { + return errors.New("ping body mismatch") + } + return nil +} diff --git a/go-libp2p/p2p/metricshelper/conn.go b/go-libp2p/p2p/metricshelper/conn.go index ef367ac..b07016c 100644 --- a/go-libp2p/p2p/metricshelper/conn.go +++ b/go-libp2p/p2p/metricshelper/conn.go @@ -2,7 +2,7 @@ package metricshelper import ma "github.com/multiformats/go-multiaddr" -var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP} +var transports = [...]int{ma.P_CIRCUIT, ma.P_WEBRTC, ma.P_WEBRTC_DIRECT, ma.P_WEBTRANSPORT, ma.P_QUIC, ma.P_QUIC_V1, ma.P_WSS, ma.P_WS, ma.P_TCP} func GetTransport(a ma.Multiaddr) string { for _, t := range transports { diff --git a/go-libp2p/p2p/muxer/mplex/conn.go b/go-libp2p/p2p/muxer/mplex/conn.go deleted file mode 100644 index ed4e847..0000000 --- a/go-libp2p/p2p/muxer/mplex/conn.go +++ /dev/null @@ -1,48 +0,0 @@ -package mplex - -import ( - "context" - - "github.com/libp2p/go-libp2p/core/network" - - mp "github.com/libp2p/go-mplex" -) - -type conn mp.Multiplex - -var _ network.MuxedConn = &conn{} - -// NewMuxedConn constructs a new Conn from a *mp.Multiplex. -func NewMuxedConn(m *mp.Multiplex) network.MuxedConn { - return (*conn)(m) -} - -func (c *conn) Close() error { - return c.mplex().Close() -} - -func (c *conn) IsClosed() bool { - return c.mplex().IsClosed() -} - -// OpenStream creates a new stream. -func (c *conn) OpenStream(ctx context.Context) (network.MuxedStream, error) { - s, err := c.mplex().NewStream(ctx) - if err != nil { - return nil, err - } - return (*stream)(s), nil -} - -// AcceptStream accepts a stream opened by the other side. -func (c *conn) AcceptStream() (network.MuxedStream, error) { - s, err := c.mplex().Accept() - if err != nil { - return nil, err - } - return (*stream)(s), nil -} - -func (c *conn) mplex() *mp.Multiplex { - return (*mp.Multiplex)(c) -} diff --git a/go-libp2p/p2p/muxer/mplex/stream.go b/go-libp2p/p2p/muxer/mplex/stream.go deleted file mode 100644 index 53e9e6d..0000000 --- a/go-libp2p/p2p/muxer/mplex/stream.go +++ /dev/null @@ -1,64 +0,0 @@ -package mplex - -import ( - "time" - - "github.com/libp2p/go-libp2p/core/network" - - mp "github.com/libp2p/go-mplex" -) - -// stream implements network.MuxedStream over mplex.Stream. -type stream mp.Stream - -var _ network.MuxedStream = &stream{} - -func (s *stream) Read(b []byte) (n int, err error) { - n, err = s.mplex().Read(b) - if err == mp.ErrStreamReset { - err = network.ErrReset - } - - return n, err -} - -func (s *stream) Write(b []byte) (n int, err error) { - n, err = s.mplex().Write(b) - if err == mp.ErrStreamReset { - err = network.ErrReset - } - - return n, err -} - -func (s *stream) Close() error { - return s.mplex().Close() -} - -func (s *stream) CloseWrite() error { - return s.mplex().CloseWrite() -} - -func (s *stream) CloseRead() error { - return s.mplex().CloseRead() -} - -func (s *stream) Reset() error { - return s.mplex().Reset() -} - -func (s *stream) SetDeadline(t time.Time) error { - return s.mplex().SetDeadline(t) -} - -func (s *stream) SetReadDeadline(t time.Time) error { - return s.mplex().SetReadDeadline(t) -} - -func (s *stream) SetWriteDeadline(t time.Time) error { - return s.mplex().SetWriteDeadline(t) -} - -func (s *stream) mplex() *mp.Stream { - return (*mp.Stream)(s) -} diff --git a/go-libp2p/p2p/muxer/mplex/transport.go b/go-libp2p/p2p/muxer/mplex/transport.go deleted file mode 100644 index 10d54d1..0000000 --- a/go-libp2p/p2p/muxer/mplex/transport.go +++ /dev/null @@ -1,28 +0,0 @@ -package mplex - -import ( - "net" - - "github.com/libp2p/go-libp2p/core/network" - - mp "github.com/libp2p/go-mplex" -) - -// DefaultTransport has default settings for Transport -var DefaultTransport = &Transport{} - -const ID = "/mplex/6.7.0" - -var _ network.Multiplexer = &Transport{} - -// Transport implements mux.Multiplexer that constructs -// mplex-backed muxed connections. -type Transport struct{} - -func (t *Transport) NewConn(nc net.Conn, isServer bool, scope network.PeerScope) (network.MuxedConn, error) { - m, err := mp.NewMultiplex(nc, isServer, scope) - if err != nil { - return nil, err - } - return NewMuxedConn(m), nil -} diff --git a/go-libp2p/p2p/muxer/mplex/transport_test.go b/go-libp2p/p2p/muxer/mplex/transport_test.go deleted file mode 100644 index 3a7d00f..0000000 --- a/go-libp2p/p2p/muxer/mplex/transport_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package mplex - -import ( - "errors" - "net" - "testing" - - "github.com/libp2p/go-libp2p/core/network" - test "github.com/libp2p/go-libp2p/p2p/muxer/testsuite" -) - -func TestDefaultTransport(t *testing.T) { - test.SubtestAll(t, DefaultTransport) -} - -type memoryScope struct { - network.PeerScope - limit int - reserved int -} - -func (m *memoryScope) ReserveMemory(size int, prio uint8) error { - if m.reserved+size > m.limit { - return errors.New("too much") - } - m.reserved += size - return nil -} - -func (m *memoryScope) ReleaseMemory(size int) { - m.reserved -= size - if m.reserved < 0 { - panic("too much memory released") - } -} - -type memoryLimitedTransport struct { - Transport -} - -func (t *memoryLimitedTransport) NewConn(nc net.Conn, isServer bool, scope network.PeerScope) (network.MuxedConn, error) { - return t.Transport.NewConn(nc, isServer, &memoryScope{ - limit: 3 * 1 << 20, - PeerScope: scope, - }) -} - -func TestDefaultTransportWithMemoryLimit(t *testing.T) { - test.SubtestAll(t, &memoryLimitedTransport{ - Transport: *DefaultTransport, - }) -} diff --git a/go-libp2p/p2p/net/connmgr/connmgr.go b/go-libp2p/p2p/net/connmgr/connmgr.go index b42a122..cf6bb58 100644 --- a/go-libp2p/p2p/net/connmgr/connmgr.go +++ b/go-libp2p/p2p/net/connmgr/connmgr.go @@ -2,6 +2,7 @@ package connmgr import ( "context" + "fmt" "sort" "sync" "sync/atomic" @@ -72,7 +73,7 @@ type segments struct { } func (ss *segments) get(p peer.ID) *segment { - return ss.buckets[byte(p[len(p)-1])] + return ss.buckets[p[len(p)-1]] } func (ss *segments) countPeers() (count int) { @@ -239,6 +240,17 @@ func (cm *BasicConnMgr) IsProtected(id peer.ID, tag string) (protected bool) { return protected } +func (cm *BasicConnMgr) CheckLimit(systemLimit connmgr.GetConnLimiter) error { + if cm.cfg.highWater > systemLimit.GetConnLimit() { + return fmt.Errorf( + "conn manager high watermark limit: %d, exceeds the system connection limit of: %d", + cm.cfg.highWater, + systemLimit.GetConnLimit(), + ) + } + return nil +} + // peerInfo stores metadata for a given peer. type peerInfo struct { id peer.ID diff --git a/go-libp2p/p2p/net/connmgr/connmgr_test.go b/go-libp2p/p2p/net/connmgr/connmgr_test.go index 8b5bbad..2c65725 100644 --- a/go-libp2p/p2p/net/connmgr/connmgr_test.go +++ b/go-libp2p/p2p/net/connmgr/connmgr_test.go @@ -662,7 +662,6 @@ func TestPeerProtectionMultipleTags(t *testing.T) { t.Error("protected connection was closed by connection manager") } } - } func TestPeerProtectionIdempotent(t *testing.T) { @@ -835,7 +834,7 @@ func TestPeerInfoSorting(t *testing.T) { p2 := &peerInfo{id: peer.ID("peer2"), temp: true} pis := peerInfos{p1, p2} pis.SortByValueAndStreams(makeSegmentsWithPeerInfos(pis), false) - require.Equal(t, pis, peerInfos{p2, p1}) + require.Equal(t, peerInfos{p2, p1}, pis) }) t.Run("starts with low-value connections", func(t *testing.T) { @@ -843,7 +842,7 @@ func TestPeerInfoSorting(t *testing.T) { p2 := &peerInfo{id: peer.ID("peer2"), value: 20} pis := peerInfos{p1, p2} pis.SortByValueAndStreams(makeSegmentsWithPeerInfos(pis), false) - require.Equal(t, pis, peerInfos{p2, p1}) + require.Equal(t, peerInfos{p2, p1}, pis) }) t.Run("prefer peers with no streams", func(t *testing.T) { @@ -859,7 +858,7 @@ func TestPeerInfoSorting(t *testing.T) { } pis := peerInfos{p2, p1} pis.SortByValueAndStreams(makeSegmentsWithPeerInfos(pis), false) - require.Equal(t, pis, peerInfos{p1, p2}) + require.Equal(t, peerInfos{p1, p2}, pis) }) t.Run("in a memory emergency, starts with incoming connections and higher streams", func(t *testing.T) { @@ -902,7 +901,7 @@ func TestPeerInfoSorting(t *testing.T) { // p3 is first because it is inactive (no streams). // p4 is second because it has the most streams and we priortize killing // connections with the higher number of streams. - require.Equal(t, pis, peerInfos{p3, p4, p2, p1}) + require.Equal(t, peerInfos{p3, p4, p2, p1}, pis) }) t.Run("in a memory emergency, starts with connections that have many streams", func(t *testing.T) { @@ -921,7 +920,7 @@ func TestPeerInfoSorting(t *testing.T) { } pis := peerInfos{p1, p2} pis.SortByValueAndStreams(makeSegmentsWithPeerInfos(pis), true) - require.Equal(t, pis, peerInfos{p2, p1}) + require.Equal(t, peerInfos{p2, p1}, pis) }) } @@ -966,3 +965,24 @@ func TestSafeConcurrency(t *testing.T) { wg.Wait() }) } + +func TestCheckLimit(t *testing.T) { + low, hi := 1, 2 + cm, err := NewConnManager(low, hi) + require.NoError(t, err) + + err = cm.CheckLimit(testLimitGetter{hi + 1}) + require.NoError(t, err) + err = cm.CheckLimit(testLimitGetter{hi}) + require.NoError(t, err) + err = cm.CheckLimit(testLimitGetter{hi - 1}) + require.Error(t, err) +} + +type testLimitGetter struct { + limit int +} + +func (g testLimitGetter) GetConnLimit() int { + return g.limit +} diff --git a/go-libp2p/p2p/net/connmgr/decay.go b/go-libp2p/p2p/net/connmgr/decay.go index bdac0be..76f1c68 100644 --- a/go-libp2p/p2p/net/connmgr/decay.go +++ b/go-libp2p/p2p/net/connmgr/decay.go @@ -320,7 +320,7 @@ func (t *decayingTag) Bump(p peer.ID, delta int) error { default: return fmt.Errorf( "unable to bump decaying tag for peer %s, tag %s, delta %d; queue full (len=%d)", - p.Pretty(), t.name, delta, len(t.trkr.bumpTagCh)) + p, t.name, delta, len(t.trkr.bumpTagCh)) } } @@ -337,7 +337,7 @@ func (t *decayingTag) Remove(p peer.ID) error { default: return fmt.Errorf( "unable to remove decaying tag for peer %s, tag %s; queue full (len=%d)", - p.Pretty(), t.name, len(t.trkr.removeTagCh)) + p, t.name, len(t.trkr.removeTagCh)) } } diff --git a/go-libp2p/p2p/net/connmgr/decay_test.go b/go-libp2p/p2p/net/connmgr/decay_test.go index e6844f1..d51ca29 100644 --- a/go-libp2p/p2p/net/connmgr/decay_test.go +++ b/go-libp2p/p2p/net/connmgr/decay_test.go @@ -49,7 +49,7 @@ func TestMultipleBumps(t *testing.T) { require.NoError(t, tag.Bump(id, 5)) waitForTag(t, mgr, id) - require.Equal(t, mgr.GetTagInfo(id).Value, 10) + require.Equal(t, 10, mgr.GetTagInfo(id).Value) require.NoError(t, tag.Bump(id, 100)) require.Eventually(t, func() bool { return mgr.GetTagInfo(id).Value == 20 }, 100*time.Millisecond, 10*time.Millisecond, "expected tag value to decay to 20") @@ -77,7 +77,7 @@ func TestMultipleTagsNoDecay(t *testing.T) { // all tags are upper-bounded, so the score must be 300 ti := mgr.GetTagInfo(id) - require.Equal(t, ti.Value, 300) + require.Equal(t, 300, ti.Value) for _, s := range []string{"beep", "bop", "foo"} { if v, ok := ti.Tags[s]; !ok || v != 100 { diff --git a/go-libp2p/p2p/net/gostream/addr.go b/go-libp2p/p2p/net/gostream/addr.go new file mode 100644 index 0000000..49d844f --- /dev/null +++ b/go-libp2p/p2p/net/gostream/addr.go @@ -0,0 +1,14 @@ +package gostream + +import "github.com/libp2p/go-libp2p/core/peer" + +// addr implements net.Addr and holds a libp2p peer ID. +type addr struct{ id peer.ID } + +// Network returns the name of the network that this address belongs to +// (libp2p). +func (a *addr) Network() string { return Network } + +// String returns the peer ID of this address in string form +// (B58-encoded). +func (a *addr) String() string { return a.id.String() } diff --git a/go-libp2p/p2p/net/gostream/conn.go b/go-libp2p/p2p/net/gostream/conn.go new file mode 100644 index 0000000..991dd2f --- /dev/null +++ b/go-libp2p/p2p/net/gostream/conn.go @@ -0,0 +1,43 @@ +package gostream + +import ( + "context" + "net" + + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/protocol" +) + +// conn is an implementation of net.Conn which wraps +// libp2p streams. +type conn struct { + network.Stream +} + +// newConn creates a conn given a libp2p stream +func newConn(s network.Stream) net.Conn { + return &conn{s} +} + +// LocalAddr returns the local network address. +func (c *conn) LocalAddr() net.Addr { + return &addr{c.Stream.Conn().LocalPeer()} +} + +// RemoteAddr returns the remote network address. +func (c *conn) RemoteAddr() net.Addr { + return &addr{c.Stream.Conn().RemotePeer()} +} + +// Dial opens a stream to the destination address +// (which should parseable to a peer ID) using the given +// host and returns it as a standard net.Conn. +func Dial(ctx context.Context, h host.Host, pid peer.ID, tag protocol.ID) (net.Conn, error) { + s, err := h.NewStream(ctx, pid, tag) + if err != nil { + return nil, err + } + return newConn(s), nil +} diff --git a/go-libp2p/p2p/net/gostream/gostream.go b/go-libp2p/p2p/net/gostream/gostream.go new file mode 100644 index 0000000..a15125b --- /dev/null +++ b/go-libp2p/p2p/net/gostream/gostream.go @@ -0,0 +1,19 @@ +// Package gostream allows to replace the standard net stack in Go +// with [LibP2P](https://github.com/libp2p/libp2p) streams. +// +// Given a libp2p.Host, gostream provides Dial() and Listen() methods which +// return implementations of net.Conn and net.Listener. +// +// Instead of the regular "host:port" addressing, `gostream` uses a Peer ID, +// and rather than a raw TCP connection, gostream will use libp2p's net.Stream. +// This means your connections will take advantage of LibP2P's multi-routes, +// NAT transversal and stream multiplexing. +// +// Note that LibP2P hosts cannot dial to themselves, so there is no possibility +// of using the same Host as server and as client. +package gostream + +// Network is the "net.Addr.Network()" name returned by +// addresses used by gostream connections. In turn, the "net.Addr.String()" will +// be a peer ID. +var Network = "libp2p" diff --git a/go-libp2p/p2p/net/gostream/gostream_test.go b/go-libp2p/p2p/net/gostream/gostream_test.go new file mode 100644 index 0000000..c024cab --- /dev/null +++ b/go-libp2p/p2p/net/gostream/gostream_test.go @@ -0,0 +1,141 @@ +package gostream + +import ( + "bufio" + "context" + "io" + "testing" + "time" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/core/protocol" + "github.com/multiformats/go-multiaddr" +) + +// newHost illustrates how to build a libp2p host with secio using +// a randomly generated key-pair +func newHost(t *testing.T, listen multiaddr.Multiaddr) host.Host { + h, err := libp2p.New( + libp2p.ListenAddrs(listen), + ) + if err != nil { + t.Fatal(err) + } + return h +} + +func TestServerClient(t *testing.T) { + m1, _ := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/10000") + m2, _ := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/10001") + srvHost := newHost(t, m1) + clientHost := newHost(t, m2) + defer srvHost.Close() + defer clientHost.Close() + + srvHost.Peerstore().AddAddrs(clientHost.ID(), clientHost.Addrs(), peerstore.PermanentAddrTTL) + clientHost.Peerstore().AddAddrs(srvHost.ID(), srvHost.Addrs(), peerstore.PermanentAddrTTL) + + var tag protocol.ID = "/testitytest" + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + done := make(chan struct{}) + go func() { + defer close(done) + listener, err := Listen(srvHost, tag) + if err != nil { + t.Error(err) + return + } + defer listener.Close() + + if listener.Addr().String() != srvHost.ID().String() { + t.Error("bad listener address") + return + } + + servConn, err := listener.Accept() + if err != nil { + t.Error(err) + return + } + defer servConn.Close() + + reader := bufio.NewReader(servConn) + for { + msg, err := reader.ReadString('\n') + if err == io.EOF { + break + } + if err != nil { + t.Error(err) + return + } + if msg != "is libp2p awesome?\n" { + t.Errorf("Bad incoming message: %s", msg) + return + } + + _, err = servConn.Write([]byte("yes it is\n")) + if err != nil { + t.Error(err) + return + } + } + }() + + clientConn, err := Dial(ctx, clientHost, srvHost.ID(), tag) + if err != nil { + t.Fatal(err) + } + + if clientConn.LocalAddr().String() != clientHost.ID().String() { + t.Fatal("Bad LocalAddr") + } + + if clientConn.RemoteAddr().String() != srvHost.ID().String() { + t.Fatal("Bad RemoteAddr") + } + + if clientConn.LocalAddr().Network() != Network { + t.Fatal("Bad Network()") + } + + err = clientConn.SetDeadline(time.Now().Add(time.Second)) + if err != nil { + t.Fatal(err) + } + + err = clientConn.SetReadDeadline(time.Now().Add(time.Second)) + if err != nil { + t.Fatal(err) + } + + err = clientConn.SetWriteDeadline(time.Now().Add(time.Second)) + if err != nil { + t.Fatal(err) + } + + _, err = clientConn.Write([]byte("is libp2p awesome?\n")) + if err != nil { + t.Fatal(err) + } + + reader := bufio.NewReader(clientConn) + resp, err := reader.ReadString('\n') + if err != nil { + t.Fatal(err) + } + + if resp != "yes it is\n" { + t.Errorf("Bad response: %s", resp) + } + + err = clientConn.Close() + if err != nil { + t.Fatal(err) + } + <-done +} diff --git a/go-libp2p/p2p/net/gostream/listener.go b/go-libp2p/p2p/net/gostream/listener.go new file mode 100644 index 0000000..250e688 --- /dev/null +++ b/go-libp2p/p2p/net/gostream/listener.go @@ -0,0 +1,71 @@ +package gostream + +import ( + "context" + "net" + + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/protocol" +) + +// listener is an implementation of net.Listener which handles +// http-tagged streams from a libp2p connection. +// A listener can be built with Listen() +type listener struct { + host host.Host + ctx context.Context + tag protocol.ID + cancel func() + streamCh chan network.Stream +} + +// Accept returns the next a connection to this listener. +// It blocks if there are no connections. Under the hood, +// connections are libp2p streams. +func (l *listener) Accept() (net.Conn, error) { + select { + case s := <-l.streamCh: + return newConn(s), nil + case <-l.ctx.Done(): + return nil, l.ctx.Err() + } +} + +// Close terminates this listener. It will no longer handle any +// incoming streams +func (l *listener) Close() error { + l.cancel() + l.host.RemoveStreamHandler(l.tag) + return nil +} + +// Addr returns the address for this listener, which is its libp2p Peer ID. +func (l *listener) Addr() net.Addr { + return &addr{l.host.ID()} +} + +// Listen provides a standard net.Listener ready to accept "connections". +// Under the hood, these connections are libp2p streams tagged with the +// given protocol.ID. +func Listen(h host.Host, tag protocol.ID) (net.Listener, error) { + ctx, cancel := context.WithCancel(context.Background()) + + l := &listener{ + host: h, + ctx: ctx, + cancel: cancel, + tag: tag, + streamCh: make(chan network.Stream), + } + + h.SetStreamHandler(tag, func(s network.Stream) { + select { + case l.streamCh <- s: + case <-ctx.Done(): + s.Reset() + } + }) + + return l, nil +} diff --git a/go-libp2p/p2p/net/mock/mock_test.go b/go-libp2p/p2p/net/mock/mock_test.go index 863e54f..aed1254 100644 --- a/go-libp2p/p2p/net/mock/mock_test.go +++ b/go-libp2p/p2p/net/mock/mock_test.go @@ -463,11 +463,11 @@ func TestRateLimiting(t *testing.T) { } rl.UpdateBandwidth(100) - if !within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond) { + if !within(rl.Limit(1), time.Millisecond*10, time.Millisecond) { t.Fatal() } - if within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond) { + if within(rl.Limit(1), time.Millisecond*10, time.Millisecond) { t.Fatal() } } diff --git a/go-libp2p/p2p/net/nat/mock_nat_test.go b/go-libp2p/p2p/net/nat/mock_nat_test.go index c7a151f..3e453f6 100644 --- a/go-libp2p/p2p/net/nat/mock_nat_test.go +++ b/go-libp2p/p2p/net/nat/mock_nat_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-nat (interfaces: NAT) +// +// Generated by this command: +// +// mockgen -package nat -destination mock_nat_test.go github.com/libp2p/go-nat NAT +// // Package nat is a generated GoMock package. package nat @@ -10,7 +15,7 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockNAT is a mock of NAT interface. @@ -46,7 +51,7 @@ func (m *MockNAT) AddPortMapping(arg0 context.Context, arg1 string, arg2 int, ar } // AddPortMapping indicates an expected call of AddPortMapping. -func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPortMapping", reflect.TypeOf((*MockNAT)(nil).AddPortMapping), arg0, arg1, arg2, arg3, arg4) } @@ -60,7 +65,7 @@ func (m *MockNAT) DeletePortMapping(arg0 context.Context, arg1 string, arg2 int) } // DeletePortMapping indicates an expected call of DeletePortMapping. -func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePortMapping", reflect.TypeOf((*MockNAT)(nil).DeletePortMapping), arg0, arg1, arg2) } diff --git a/go-libp2p/p2p/net/nat/nat_test.go b/go-libp2p/p2p/net/nat/nat_test.go index ea47edc..50e1eb3 100644 --- a/go-libp2p/p2p/net/nat/nat_test.go +++ b/go-libp2p/p2p/net/nat/nat_test.go @@ -9,11 +9,11 @@ import ( "github.com/libp2p/go-nat" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) -//go:generate sh -c "go run github.com/golang/mock/mockgen -package nat -destination mock_nat_test.go github.com/libp2p/go-nat NAT" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package nat -destination mock_nat_test.go github.com/libp2p/go-nat NAT" func setupMockNAT(t *testing.T) (mockNAT *MockNAT, reset func()) { t.Helper() diff --git a/go-libp2p/p2p/net/reuseport/dialer.go b/go-libp2p/p2p/net/reuseport/dialer.go index 2efc02d..ec3769a 100644 --- a/go-libp2p/p2p/net/reuseport/dialer.go +++ b/go-libp2p/p2p/net/reuseport/dialer.go @@ -33,7 +33,7 @@ func randAddr(addrs []*net.TCPAddr) *net.TCPAddr { // // In-order: // -// 1. If we're _explicitly_ listening on the prefered source address for the destination address +// 1. If we're _explicitly_ listening on the preferred source address for the destination address // (per the system's routes), we'll use that listener's port as the source port. // 2. If we're listening on one or more _unspecified_ addresses (zero address), we'll pick a source // port from one of these listener's. diff --git a/go-libp2p/p2p/net/reuseport/transport_test.go b/go-libp2p/p2p/net/reuseport/transport_test.go index 88f9cdb..92ccf17 100644 --- a/go-libp2p/p2p/net/reuseport/transport_test.go +++ b/go-libp2p/p2p/net/reuseport/transport_test.go @@ -1,9 +1,11 @@ package reuseport import ( + "context" "net" "runtime" "testing" + "time" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" @@ -64,8 +66,11 @@ func acceptOne(t *testing.T, listener manet.Listener) <-chan manet.Conn { func dialOne(t *testing.T, tr *Transport, listener manet.Listener, expected ...int) int { t.Helper() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + connChan := acceptOne(t, listener) - c, err := tr.Dial(listener.Multiaddr()) + c, err := tr.DialContext(ctx, listener.Multiaddr()) if err != nil { t.Fatal(err) } diff --git a/go-libp2p/p2p/net/swarm/addrs.go b/go-libp2p/p2p/net/swarm/addrs.go deleted file mode 100644 index 392900e..0000000 --- a/go-libp2p/p2p/net/swarm/addrs.go +++ /dev/null @@ -1,39 +0,0 @@ -package swarm - -import ( - ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" -) - -// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml -var lowTimeoutFilters = ma.NewFilters() - -func init() { - for _, p := range []string{ - "/ip4/10.0.0.0/ipcidr/8", - "/ip4/100.64.0.0/ipcidr/10", - "/ip4/169.254.0.0/ipcidr/16", - "/ip4/172.16.0.0/ipcidr/12", - "/ip4/192.0.0.0/ipcidr/24", - "/ip4/192.0.0.0/ipcidr/29", - "/ip4/192.0.0.8/ipcidr/32", - "/ip4/192.0.0.170/ipcidr/32", - "/ip4/192.0.0.171/ipcidr/32", - "/ip4/192.0.2.0/ipcidr/24", - "/ip4/192.168.0.0/ipcidr/16", - "/ip4/198.18.0.0/ipcidr/15", - "/ip4/198.51.100.0/ipcidr/24", - "/ip4/203.0.113.0/ipcidr/24", - "/ip4/240.0.0.0/ipcidr/4", - } { - f, err := ma.NewMultiaddr(p) - if err != nil { - panic("error in lowTimeoutFilters init: " + err.Error()) - } - ipnet, err := manet.MultiaddrToIPNet(f) - if err != nil { - panic("error in lowTimeoutFilters init: " + err.Error()) - } - lowTimeoutFilters.AddFilter(*ipnet, ma.ActionDeny) - } -} diff --git a/go-libp2p/p2p/net/swarm/black_hole_detector.go b/go-libp2p/p2p/net/swarm/black_hole_detector.go index 078b112..dd7849e 100644 --- a/go-libp2p/p2p/net/swarm/black_hole_detector.go +++ b/go-libp2p/p2p/net/swarm/black_hole_detector.go @@ -178,7 +178,7 @@ type blackHoleDetector struct { } // FilterAddrs filters the peer's addresses removing black holed addresses -func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { +func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) (valid []ma.Multiaddr, blackHoled []ma.Multiaddr) { hasUDP, hasIPv6 := false, false for _, a := range addrs { if !manet.IsPublicAddr(a) { @@ -202,6 +202,7 @@ func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { ipv6Res = d.ipv6.HandleRequest() } + blackHoled = make([]ma.Multiaddr, 0, len(addrs)) return ma.FilterAddrs( addrs, func(a ma.Multiaddr) bool { @@ -218,14 +219,16 @@ func (d *blackHoleDetector) FilterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { } if udpRes == blackHoleResultBlocked && isProtocolAddr(a, ma.P_UDP) { + blackHoled = append(blackHoled, a) return false } if ipv6Res == blackHoleResultBlocked && isProtocolAddr(a, ma.P_IP6) { + blackHoled = append(blackHoled, a) return false } return true }, - ) + ), blackHoled } // RecordResult updates the state of the relevant `blackHoleFilter`s for addr diff --git a/go-libp2p/p2p/net/swarm/black_hole_detector_test.go b/go-libp2p/p2p/net/swarm/black_hole_detector_test.go index 7b10fc8..1ab2cbe 100644 --- a/go-libp2p/p2p/net/swarm/black_hole_detector_test.go +++ b/go-libp2p/p2p/net/swarm/black_hole_detector_test.go @@ -85,7 +85,7 @@ func TestBlackHoleDetectorInApplicableAddress(t *testing.T) { ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1"), } for i := 0; i < 1000; i++ { - filteredAddrs := bhd.FilterAddrs(addrs) + filteredAddrs, _ := bhd.FilterAddrs(addrs) require.ElementsMatch(t, addrs, filteredAddrs) for j := 0; j < len(addrs); j++ { bhd.RecordResult(addrs[j], false) @@ -101,20 +101,29 @@ func TestBlackHoleDetectorUDPDisabled(t *testing.T) { for i := 0; i < 100; i++ { bhd.RecordResult(publicAddr, false) } - addrs := []ma.Multiaddr{publicAddr, privAddr} - require.ElementsMatch(t, addrs, bhd.FilterAddrs(addrs)) + wantAddrs := []ma.Multiaddr{publicAddr, privAddr} + wantRemovedAddrs := make([]ma.Multiaddr, 0) + + gotAddrs, gotRemovedAddrs := bhd.FilterAddrs(wantAddrs) + require.ElementsMatch(t, wantAddrs, gotAddrs) + require.ElementsMatch(t, wantRemovedAddrs, gotRemovedAddrs) } func TestBlackHoleDetectorIPv6Disabled(t *testing.T) { udpConfig := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5} bhd := newBlackHoleDetector(udpConfig, blackHoleConfig{Enabled: false}, nil) - publicAddr := ma.StringCast("/ip6/1::1/tcp/1234") + publicAddr := ma.StringCast("/ip6/2001::1/tcp/1234") privAddr := ma.StringCast("/ip6/::1/tcp/1234") - addrs := []ma.Multiaddr{publicAddr, privAddr} for i := 0; i < 100; i++ { bhd.RecordResult(publicAddr, false) } - require.ElementsMatch(t, addrs, bhd.FilterAddrs(addrs)) + + wantAddrs := []ma.Multiaddr{publicAddr, privAddr} + wantRemovedAddrs := make([]ma.Multiaddr, 0) + + gotAddrs, gotRemovedAddrs := bhd.FilterAddrs(wantAddrs) + require.ElementsMatch(t, wantAddrs, gotAddrs) + require.ElementsMatch(t, wantRemovedAddrs, gotRemovedAddrs) } func TestBlackHoleDetectorProbes(t *testing.T) { @@ -122,13 +131,13 @@ func TestBlackHoleDetectorProbes(t *testing.T) { udp: &blackHoleFilter{n: 2, minSuccesses: 1, name: "udp"}, ipv6: &blackHoleFilter{n: 3, minSuccesses: 1, name: "ipv6"}, } - udp6Addr := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + udp6Addr := ma.StringCast("/ip6/2001::1/udp/1234/quic-v1") addrs := []ma.Multiaddr{udp6Addr} for i := 0; i < 3; i++ { bhd.RecordResult(udp6Addr, false) } for i := 1; i < 100; i++ { - filteredAddrs := bhd.FilterAddrs(addrs) + filteredAddrs, _ := bhd.FilterAddrs(addrs) if i%2 == 0 || i%3 == 0 { if len(filteredAddrs) == 0 { t.Fatalf("expected probe to be allowed irrespective of the state of other black hole filter") @@ -143,11 +152,11 @@ func TestBlackHoleDetectorProbes(t *testing.T) { } func TestBlackHoleDetectorAddrFiltering(t *testing.T) { - udp6Pub := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + udp6Pub := ma.StringCast("/ip6/2001::1/udp/1234/quic-v1") udp6Pri := ma.StringCast("/ip6/::1/udp/1234/quic-v1") - upd4Pub := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1") + udp4Pub := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1") udp4Pri := ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1") - tcp6Pub := ma.StringCast("/ip6/1::1/tcp/1234/quic-v1") + tcp6Pub := ma.StringCast("/ip6/2001::1/tcp/1234/quic-v1") tcp6Pri := ma.StringCast("/ip6/::1/tcp/1234/quic-v1") tcp4Pub := ma.StringCast("/ip4/1.2.3.4/tcp/1234/quic-v1") tcp4Pri := ma.StringCast("/ip4/192.168.1.5/tcp/1234/quic-v1") @@ -158,7 +167,7 @@ func TestBlackHoleDetectorAddrFiltering(t *testing.T) { ipv6: &blackHoleFilter{n: 100, minSuccesses: 10, name: "ipv6"}, } for i := 0; i < 100; i++ { - bhd.RecordResult(upd4Pub, !udpBlocked) + bhd.RecordResult(udp4Pub, !udpBlocked) } for i := 0; i < 100; i++ { bhd.RecordResult(tcp6Pub, !ipv6Blocked) @@ -166,18 +175,27 @@ func TestBlackHoleDetectorAddrFiltering(t *testing.T) { return bhd } - allInput := []ma.Multiaddr{udp6Pub, udp6Pri, upd4Pub, udp4Pri, tcp6Pub, tcp6Pri, + allInput := []ma.Multiaddr{udp6Pub, udp6Pri, udp4Pub, udp4Pri, tcp6Pub, tcp6Pri, tcp4Pub, tcp4Pri} udpBlockedOutput := []ma.Multiaddr{udp6Pri, udp4Pri, tcp6Pub, tcp6Pri, tcp4Pub, tcp4Pri} + udpPublicAddrs := []ma.Multiaddr{udp6Pub, udp4Pub} bhd := makeBHD(true, false) - require.ElementsMatch(t, udpBlockedOutput, bhd.FilterAddrs(allInput)) + gotAddrs, gotRemovedAddrs := bhd.FilterAddrs(allInput) + require.ElementsMatch(t, udpBlockedOutput, gotAddrs) + require.ElementsMatch(t, udpPublicAddrs, gotRemovedAddrs) - ip6BlockedOutput := []ma.Multiaddr{udp6Pri, upd4Pub, udp4Pri, tcp6Pri, tcp4Pub, tcp4Pri} + ip6BlockedOutput := []ma.Multiaddr{udp6Pri, udp4Pub, udp4Pri, tcp6Pri, tcp4Pub, tcp4Pri} + ip6PublicAddrs := []ma.Multiaddr{udp6Pub, tcp6Pub} bhd = makeBHD(false, true) - require.ElementsMatch(t, ip6BlockedOutput, bhd.FilterAddrs(allInput)) + gotAddrs, gotRemovedAddrs = bhd.FilterAddrs(allInput) + require.ElementsMatch(t, ip6BlockedOutput, gotAddrs) + require.ElementsMatch(t, ip6PublicAddrs, gotRemovedAddrs) bothBlockedOutput := []ma.Multiaddr{udp6Pri, udp4Pri, tcp6Pri, tcp4Pub, tcp4Pri} + bothPublicAddrs := []ma.Multiaddr{udp6Pub, tcp6Pub, udp4Pub} bhd = makeBHD(true, true) - require.ElementsMatch(t, bothBlockedOutput, bhd.FilterAddrs(allInput)) + gotAddrs, gotRemovedAddrs = bhd.FilterAddrs(allInput) + require.ElementsMatch(t, bothBlockedOutput, gotAddrs) + require.ElementsMatch(t, bothPublicAddrs, gotRemovedAddrs) } diff --git a/go-libp2p/p2p/net/swarm/connectedness_event_emitter.go b/go-libp2p/p2p/net/swarm/connectedness_event_emitter.go new file mode 100644 index 0000000..07db583 --- /dev/null +++ b/go-libp2p/p2p/net/swarm/connectedness_event_emitter.go @@ -0,0 +1,143 @@ +package swarm + +import ( + "context" + "sync" + + "github.com/libp2p/go-libp2p/core/event" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" +) + +// connectednessEventEmitter emits PeerConnectednessChanged events. +// We ensure that for any peer we connected to we always sent atleast 1 NotConnected Event after +// the peer disconnects. This is because peers can observe a connection before they are notified +// of the connection by a peer connectedness changed event. +type connectednessEventEmitter struct { + mx sync.RWMutex + // newConns is the channel that holds the peerIDs we recently connected to + newConns chan peer.ID + removeConnsMx sync.Mutex + // removeConns is a slice of peerIDs we have recently closed connections to + removeConns []peer.ID + // lastEvent is the last connectedness event sent for a particular peer. + lastEvent map[peer.ID]network.Connectedness + // connectedness is the function that gives the peers current connectedness state + connectedness func(peer.ID) network.Connectedness + // emitter is the PeerConnectednessChanged event emitter + emitter event.Emitter + wg sync.WaitGroup + removeConnNotif chan struct{} + ctx context.Context + cancel context.CancelFunc +} + +func newConnectednessEventEmitter(connectedness func(peer.ID) network.Connectedness, emitter event.Emitter) *connectednessEventEmitter { + ctx, cancel := context.WithCancel(context.Background()) + c := &connectednessEventEmitter{ + newConns: make(chan peer.ID, 32), + lastEvent: make(map[peer.ID]network.Connectedness), + removeConnNotif: make(chan struct{}, 1), + connectedness: connectedness, + emitter: emitter, + ctx: ctx, + cancel: cancel, + } + c.wg.Add(1) + go c.runEmitter() + return c +} + +func (c *connectednessEventEmitter) AddConn(p peer.ID) { + c.mx.RLock() + defer c.mx.RUnlock() + if c.ctx.Err() != nil { + return + } + + c.newConns <- p +} + +func (c *connectednessEventEmitter) RemoveConn(p peer.ID) { + c.mx.RLock() + defer c.mx.RUnlock() + if c.ctx.Err() != nil { + return + } + + c.removeConnsMx.Lock() + // This queue is roughly bounded by the total number of added connections we + // have. If consumers of connectedness events are slow, we apply + // backpressure to AddConn operations. + // + // We purposefully don't block/backpressure here to avoid deadlocks, since it's + // reasonable for a consumer of the event to want to remove a connection. + c.removeConns = append(c.removeConns, p) + + c.removeConnsMx.Unlock() + + select { + case c.removeConnNotif <- struct{}{}: + default: + } +} + +func (c *connectednessEventEmitter) Close() { + c.cancel() + c.wg.Wait() +} + +func (c *connectednessEventEmitter) runEmitter() { + defer c.wg.Done() + for { + select { + case p := <-c.newConns: + c.notifyPeer(p, true) + case <-c.removeConnNotif: + c.sendConnRemovedNotifications() + case <-c.ctx.Done(): + c.mx.Lock() // Wait for all pending AddConn & RemoveConn operations to complete + defer c.mx.Unlock() + for { + select { + case p := <-c.newConns: + c.notifyPeer(p, true) + case <-c.removeConnNotif: + c.sendConnRemovedNotifications() + default: + return + } + } + } + } +} + +// notifyPeer sends the peer connectedness event using the emitter. +// Use forceNotConnectedEvent = true to send a NotConnected event even if +// no Connected event was sent for this peer. +// In case a peer is disconnected before we sent the Connected event, we still +// send the Disconnected event because a connection to the peer can be observed +// in such cases. +func (c *connectednessEventEmitter) notifyPeer(p peer.ID, forceNotConnectedEvent bool) { + oldState := c.lastEvent[p] + c.lastEvent[p] = c.connectedness(p) + if c.lastEvent[p] == network.NotConnected { + delete(c.lastEvent, p) + } + if (forceNotConnectedEvent && c.lastEvent[p] == network.NotConnected) || c.lastEvent[p] != oldState { + c.emitter.Emit(event.EvtPeerConnectednessChanged{ + Peer: p, + Connectedness: c.lastEvent[p], + }) + } +} + +func (c *connectednessEventEmitter) sendConnRemovedNotifications() { + c.removeConnsMx.Lock() + removeConns := c.removeConns + c.removeConns = nil + c.removeConnsMx.Unlock() + for _, p := range removeConns { + c.notifyPeer(p, false) + } +} diff --git a/go-libp2p/p2p/net/swarm/dial_error.go b/go-libp2p/p2p/net/swarm/dial_error.go index 711ee06..4de6822 100644 --- a/go-libp2p/p2p/net/swarm/dial_error.go +++ b/go-libp2p/p2p/net/swarm/dial_error.go @@ -30,10 +30,7 @@ func (e *DialError) recordErr(addr ma.Multiaddr, err error) { e.Skipped++ return } - e.DialErrors = append(e.DialErrors, TransportError{ - Address: addr, - Cause: err, - }) + e.DialErrors = append(e.DialErrors, TransportError{Address: addr, Cause: err}) } func (e *DialError) Error() string { @@ -51,9 +48,19 @@ func (e *DialError) Error() string { return builder.String() } -// Unwrap implements https://godoc.org/golang.org/x/xerrors#Wrapper. -func (e *DialError) Unwrap() error { - return e.Cause +func (e *DialError) Unwrap() []error { + if e == nil { + return nil + } + + errs := make([]error, len(e.DialErrors)+1) + if e.Cause != nil { + errs = append(errs, e.Cause) + } + for i := 0; i < len(e.DialErrors); i++ { + errs = append(errs, &e.DialErrors[i]) + } + return errs } var _ error = (*DialError)(nil) @@ -68,4 +75,8 @@ func (e *TransportError) Error() string { return fmt.Sprintf("failed to dial %s: %s", e.Address, e.Cause) } +func (e *TransportError) Unwrap() error { + return e.Cause +} + var _ error = (*TransportError)(nil) diff --git a/go-libp2p/p2p/net/swarm/dial_error_test.go b/go-libp2p/p2p/net/swarm/dial_error_test.go new file mode 100644 index 0000000..3231d6f --- /dev/null +++ b/go-libp2p/p2p/net/swarm/dial_error_test.go @@ -0,0 +1,51 @@ +package swarm + +import ( + "net" + "os" + "testing" + + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestTransportError(t *testing.T) { + aa := ma.StringCast("/ip4/1.2.3.4/tcp/1234") + te := &TransportError{Address: aa, Cause: ErrDialBackoff} + require.ErrorIs(t, te, ErrDialBackoff, "TransportError should implement Unwrap") +} + +func TestDialError(t *testing.T) { + de := &DialError{Peer: "pid", Cause: ErrGaterDisallowedConnection} + require.ErrorIs(t, de, ErrGaterDisallowedConnection, + "DialError Unwrap should handle DialError.Cause") + require.ErrorIs(t, de, de, "DialError Unwrap should handle match to self") + + aa := ma.StringCast("/ip4/1.2.3.4/tcp/1234") + ab := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + de = &DialError{ + Peer: "pid", + DialErrors: []TransportError{ + {Address: aa, Cause: ErrDialBackoff}, {Address: ab, Cause: ErrNoTransport}, + }, + } + require.ErrorIs(t, de, ErrDialBackoff, "DialError.Unwrap should traverse TransportErrors") + require.ErrorIs(t, de, ErrNoTransport, "DialError.Unwrap should traverse TransportErrors") + + de = &DialError{ + Peer: "pid", + DialErrors: []TransportError{{Address: ab, Cause: ErrNoTransport}, + // wrapped error 2 levels deep + {Address: aa, Cause: &net.OpError{ + Op: "write", + Net: "tcp", + Err: &os.SyscallError{ + Syscall: "connect", + Err: os.ErrPermission, + }, + }}, + }, + } + require.ErrorIs(t, de, os.ErrPermission, "DialError.Unwrap should traverse TransportErrors") + +} diff --git a/go-libp2p/p2p/net/swarm/dial_ranker.go b/go-libp2p/p2p/net/swarm/dial_ranker.go index 3725884..7e58876 100644 --- a/go-libp2p/p2p/net/swarm/dial_ranker.go +++ b/go-libp2p/p2p/net/swarm/dial_ranker.go @@ -58,8 +58,19 @@ func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { // 3. If a QUIC or WebTransport address is present, TCP addresses dials are delayed relative to the last QUIC dial: // We prefer to end up with a QUIC connection. For public addresses, the delay introduced is 250ms (PublicTCPDelay), // and for private addresses 30ms (PrivateTCPDelay). +// 4. For the TCP addresses we follow a strategy similar to QUIC with an optimisation for handling the long TCP +// handshake time described in 6. If both IPv6 TCP and IPv4 TCP addresses are present, we do a Happy Eyeballs +// style ranking. First dial the IPv6 TCP address with the lowest port. After this, dial the IPv4 TCP address +// with the lowest port delayed by 250ms (PublicTCPDelay) for public addresses, and 30ms (PrivateTCPDelay) +// for local addresses. After this we dial all the rest of the addresses delayed by 250ms (PublicTCPDelay) for +// public addresses, and 30ms (PrivateTCPDelay) for local addresses. +// 5. If only one of TCP IPv6 or TCP IPv4 addresses are present, dial the TCP address with the lowest port +// first. After this we dial the rest of the TCP addresses delayed by 250ms (PublicTCPDelay) for public +// addresses, and 30ms (PrivateTCPDelay) for local addresses. +// 6. When a TCP socket is connected and awaiting security and muxer upgrade, we stop new dials for 2*PrivateTCPDelay +// to allow for the upgrade to complete. // -// We dial lowest ports first for QUIC addresses as they are more likely to be the listen port. +// We dial lowest ports first as they are more likely to be the listen port. func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { relay, addrs := filterAddrs(addrs, isRelayAddr) pvt, addrs := filterAddrs(addrs, manet.IsPrivateAddr) @@ -88,22 +99,57 @@ func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { // addresses relative to direct addresses. func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.Duration, offset time.Duration) []network.AddrDelay { + if len(addrs) == 0 { + return nil + } sort.Slice(addrs, func(i, j int) bool { return score(addrs[i]) < score(addrs[j]) }) - // If the first address is (QUIC, IPv6), make the second address (QUIC, IPv4). - happyEyeballs := false - if len(addrs) > 0 { + // addrs is now sorted by (Transport, IPVersion). Reorder addrs for happy eyeballs dialing. + // For QUIC and TCP, if we have both IPv6 and IPv4 addresses, move the + // highest priority IPv4 address to the second position. + happyEyeballsQUIC := false + happyEyeballsTCP := false + // tcpStartIdx is the index of the first TCP Address + var tcpStartIdx int + { + i := 0 + // If the first QUIC address is IPv6 move the first QUIC IPv4 address to second position if isQUICAddr(addrs[0]) && isProtocolAddr(addrs[0], ma.P_IP6) { - for i := 1; i < len(addrs); i++ { - if isQUICAddr(addrs[i]) && isProtocolAddr(addrs[i], ma.P_IP4) { - // make IPv4 address the second element - if i > 1 { - a := addrs[i] - copy(addrs[2:], addrs[1:i]) + for j := 1; j < len(addrs); j++ { + if isQUICAddr(addrs[j]) && isProtocolAddr(addrs[j], ma.P_IP4) { + // The first IPv4 address is at position j + // Move the jth element at position 1 shifting the affected elements + if j > 1 { + a := addrs[j] + copy(addrs[2:], addrs[1:j]) addrs[1] = a } - happyEyeballs = true + happyEyeballsQUIC = true + i = j + 1 + break + } + } + } + + for tcpStartIdx = i; tcpStartIdx < len(addrs); tcpStartIdx++ { + if isProtocolAddr(addrs[tcpStartIdx], ma.P_TCP) { + break + } + } + + // If the first TCP address is IPv6 move the first TCP IPv4 address to second position + if tcpStartIdx < len(addrs) && isProtocolAddr(addrs[tcpStartIdx], ma.P_IP6) { + for j := tcpStartIdx + 1; j < len(addrs); j++ { + if isProtocolAddr(addrs[j], ma.P_TCP) && isProtocolAddr(addrs[j], ma.P_IP4) { + // First TCP IPv4 address is at position j, move it to position tcpStartIdx+1 + // which is the second priority TCP address + if j > tcpStartIdx+1 { + a := addrs[j] + copy(addrs[tcpStartIdx+2:], addrs[tcpStartIdx+1:j]) + addrs[tcpStartIdx+1] = a + } + happyEyeballsTCP = true break } } @@ -111,25 +157,42 @@ func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.D } res := make([]network.AddrDelay, 0, len(addrs)) - - var totalTCPDelay time.Duration + var tcpFirstDialDelay time.Duration for i, addr := range addrs { var delay time.Duration switch { case isQUICAddr(addr): - // For QUIC addresses we dial an IPv6 address, then after quicDelay an IPv4 - // address, then after quicDelay we dial rest of the addresses. + // We dial an IPv6 address, then after quicDelay an IPv4 + // address, then after a further quicDelay we dial the rest of the addresses. if i == 1 { delay = quicDelay } - if i > 1 && happyEyeballs { - delay = 2 * quicDelay - } else if i > 1 { - delay = quicDelay + if i > 1 { + // If we have happy eyeballs for QUIC, dials after the second position + // will be delayed by 2*quicDelay + if happyEyeballsQUIC { + delay = 2 * quicDelay + } else { + delay = quicDelay + } } - totalTCPDelay = delay + tcpDelay + tcpFirstDialDelay = delay + tcpDelay case isProtocolAddr(addr, ma.P_TCP): - delay = totalTCPDelay + // We dial an IPv6 address, then after tcpDelay an IPv4 + // address, then after a further tcpDelay we dial the rest of the addresses. + if i == tcpStartIdx+1 { + delay = tcpDelay + } + if i > tcpStartIdx+1 { + // If we have happy eyeballs for TCP, dials after the second position + // will be delayed by 2*tcpDelay + if happyEyeballsTCP { + delay = 2 * tcpDelay + } else { + delay = tcpDelay + } + } + delay += tcpFirstDialDelay } res = append(res, network.AddrDelay{Addr: addr, Delay: offset + delay}) } diff --git a/go-libp2p/p2p/net/swarm/dial_ranker_test.go b/go-libp2p/p2p/net/swarm/dial_ranker_test.go index 60fbfab..5ef3cc2 100644 --- a/go-libp2p/p2p/net/swarm/dial_ranker_test.go +++ b/go-libp2p/p2p/net/swarm/dial_ranker_test.go @@ -20,14 +20,14 @@ func sortAddrDelays(addrDelays []network.AddrDelay) { } func TestNoDelayDialRanker(t *testing.T) { - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") - q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") q3v1 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") - q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic") + q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic-v1") t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") testCase := []struct { @@ -70,14 +70,10 @@ func TestNoDelayDialRanker(t *testing.T) { } func TestDelayRankerQUICDelay(t *testing.T) { - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") - q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") q3v1 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") - q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic") q1v16 := ma.StringCast("/ip6/1::2/udp/1/quic-v1") q2v16 := ma.StringCast("/ip6/1::2/udp/2/quic-v1") @@ -90,12 +86,11 @@ func TestDelayRankerQUICDelay(t *testing.T) { }{ { name: "quic-ipv4", - addrs: []ma.Multiaddr{q1, q2, q3, q4}, + addrs: []ma.Multiaddr{q1v1, q2v1, q3v1}, output: []network.AddrDelay{ - {Addr: q1, Delay: 0}, - {Addr: q2, Delay: PublicQUICDelay}, - {Addr: q3, Delay: PublicQUICDelay}, - {Addr: q4, Delay: PublicQUICDelay}, + {Addr: q1v1, Delay: 0}, + {Addr: q2v1, Delay: PublicQUICDelay}, + {Addr: q3v1, Delay: PublicQUICDelay}, }, }, { @@ -109,37 +104,29 @@ func TestDelayRankerQUICDelay(t *testing.T) { }, { name: "quic-ip4-ip6", - addrs: []ma.Multiaddr{q1, q1v16, q2v1, q3, q4}, + addrs: []ma.Multiaddr{q1v16, q2v1}, output: []network.AddrDelay{ {Addr: q1v16, Delay: 0}, {Addr: q2v1, Delay: PublicQUICDelay}, - {Addr: q1, Delay: 2 * PublicQUICDelay}, - {Addr: q3, Delay: 2 * PublicQUICDelay}, - {Addr: q4, Delay: 2 * PublicQUICDelay}, }, }, { name: "quic-quic-v1-webtransport", - addrs: []ma.Multiaddr{q1v16, q1, q2, q3, q4, q1v1, q2v1, q3v1, wt1}, + addrs: []ma.Multiaddr{q1v16, q1v1, q2v1, q3v1, wt1}, output: []network.AddrDelay{ {Addr: q1v16, Delay: 0}, {Addr: q1v1, Delay: PublicQUICDelay}, {Addr: q2v1, Delay: 2 * PublicQUICDelay}, {Addr: q3v1, Delay: 2 * PublicQUICDelay}, - {Addr: q1, Delay: 2 * PublicQUICDelay}, - {Addr: q2, Delay: 2 * PublicQUICDelay}, - {Addr: q3, Delay: 2 * PublicQUICDelay}, - {Addr: q4, Delay: 2 * PublicQUICDelay}, {Addr: wt1, Delay: 2 * PublicQUICDelay}, }, }, { name: "wt-ranking", - addrs: []ma.Multiaddr{q1v16, q2v16, q3v16, q2, wt1}, + addrs: []ma.Multiaddr{q1v16, q2v16, q3v16, wt1}, output: []network.AddrDelay{ {Addr: q1v16, Delay: 0}, - {Addr: q2, Delay: PublicQUICDelay}, - {Addr: wt1, Delay: 2 * PublicQUICDelay}, + {Addr: wt1, Delay: PublicQUICDelay}, {Addr: q2v16, Delay: 2 * PublicQUICDelay}, {Addr: q3v16, Delay: 2 * PublicQUICDelay}, }, @@ -164,11 +151,8 @@ func TestDelayRankerQUICDelay(t *testing.T) { } func TestDelayRankerTCPDelay(t *testing.T) { - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") - q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") q1v16 := ma.StringCast("/ip6/1::2/udp/1/quic-v1") q2v16 := ma.StringCast("/ip6/1::2/udp/2/quic-v1") @@ -177,6 +161,7 @@ func TestDelayRankerTCPDelay(t *testing.T) { t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") t1v6 := ma.StringCast("/ip6/1::2/tcp/1") t2 := ma.StringCast("/ip4/1.2.3.4/tcp/2") + t3 := ma.StringCast("/ip4/1.2.3.4/tcp/3") testCase := []struct { name string @@ -185,39 +170,63 @@ func TestDelayRankerTCPDelay(t *testing.T) { }{ { name: "quic-with-tcp-ip6-ip4", - addrs: []ma.Multiaddr{q1, q1v1, q1v16, q2v16, q3v16, q2v1, t1, t2}, + addrs: []ma.Multiaddr{q1v1, q1v16, q2v16, q3v16, q2v1, t1, t1v6, t2, t3}, output: []network.AddrDelay{ {Addr: q1v16, Delay: 0}, {Addr: q1v1, Delay: PublicQUICDelay}, - {Addr: q1, Delay: 2 * PublicQUICDelay}, {Addr: q2v16, Delay: 2 * PublicQUICDelay}, {Addr: q3v16, Delay: 2 * PublicQUICDelay}, {Addr: q2v1, Delay: 2 * PublicQUICDelay}, - {Addr: t1, Delay: 3 * PublicQUICDelay}, - {Addr: t2, Delay: 3 * PublicQUICDelay}, + {Addr: t1v6, Delay: 3 * PublicQUICDelay}, + {Addr: t1, Delay: 4 * PublicQUICDelay}, + {Addr: t2, Delay: 5 * PublicQUICDelay}, + {Addr: t3, Delay: 5 * PublicQUICDelay}, }, }, { name: "quic-ip4-with-tcp", - addrs: []ma.Multiaddr{q1, q2, q3, t1, t2, t1v6}, + addrs: []ma.Multiaddr{q1v1, t2, t1v6, t1}, output: []network.AddrDelay{ - {Addr: q1, Delay: 0}, - {Addr: q2, Delay: PublicQUICDelay}, - {Addr: q3, Delay: PublicQUICDelay}, - {Addr: t1, Delay: PublicQUICDelay + PublicTCPDelay}, - {Addr: t2, Delay: PublicQUICDelay + PublicTCPDelay}, - {Addr: t1v6, Delay: PublicQUICDelay + PublicTCPDelay}, + {Addr: q1v1, Delay: 0}, + {Addr: t1v6, Delay: PublicQUICDelay}, + {Addr: t1, Delay: 2 * PublicQUICDelay}, + {Addr: t2, Delay: 3 * PublicQUICDelay}, + }, + }, + { + name: "quic-ip4-with-tcp-ipv4", + addrs: []ma.Multiaddr{q1v1, t2, t3, t1}, + output: []network.AddrDelay{ + {Addr: q1v1, Delay: 0}, + {Addr: t1, Delay: PublicTCPDelay}, + {Addr: t2, Delay: 2 * PublicQUICDelay}, + {Addr: t3, Delay: 2 * PublicTCPDelay}, + }, + }, + { + name: "quic-ip4-with-two-tcp", + addrs: []ma.Multiaddr{q1v1, t1v6, t2}, + output: []network.AddrDelay{ + {Addr: q1v1, Delay: 0}, + {Addr: t1v6, Delay: PublicTCPDelay}, + {Addr: t2, Delay: 2 * PublicTCPDelay}, }, }, { name: "tcp-ip4-ip6", - addrs: []ma.Multiaddr{t1, t2, t1v6}, + addrs: []ma.Multiaddr{t1, t2, t1v6, t3}, output: []network.AddrDelay{ {Addr: t1v6, Delay: 0}, - {Addr: t1, Delay: 0}, - {Addr: t2, Delay: 0}, + {Addr: t1, Delay: PublicTCPDelay}, + {Addr: t2, Delay: 2 * PublicTCPDelay}, + {Addr: t3, Delay: 2 * PublicTCPDelay}, }, }, + { + name: "empty", + addrs: []ma.Multiaddr{}, + output: []network.AddrDelay{}, + }, } for _, tc := range testCase { t.Run(tc.name, func(t *testing.T) { @@ -238,8 +247,8 @@ func TestDelayRankerTCPDelay(t *testing.T) { } func TestDelayRankerRelay(t *testing.T) { - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") pid := test.RandPeerIDFatal(t) r1 := ma.StringCast(fmt.Sprintf("/ip4/1.2.3.4/tcp/1/p2p-circuit/p2p/%s", pid)) diff --git a/go-libp2p/p2p/net/swarm/dial_sync.go b/go-libp2p/p2p/net/swarm/dial_sync.go index 2a8ff43..3cc8547 100644 --- a/go-libp2p/p2p/net/swarm/dial_sync.go +++ b/go-libp2p/p2p/net/swarm/dial_sync.go @@ -2,6 +2,7 @@ package swarm import ( "context" + "errors" "sync" "github.com/libp2p/go-libp2p/core/network" @@ -11,6 +12,9 @@ import ( // dialWorkerFunc is used by dialSync to spawn a new dial worker type dialWorkerFunc func(peer.ID, <-chan dialRequest) +// errConcurrentDialSuccessful is used to signal that a concurrent dial succeeded +var errConcurrentDialSuccessful = errors.New("concurrent dial successful") + // newDialSync constructs a new dialSync func newDialSync(worker dialWorkerFunc) *dialSync { return &dialSync{ @@ -30,17 +34,12 @@ type dialSync struct { type activeDial struct { refCnt int - ctx context.Context - cancel func() + ctx context.Context + cancelCause func(error) reqch chan dialRequest } -func (ad *activeDial) close() { - ad.cancel() - close(ad.reqch) -} - func (ad *activeDial) dial(ctx context.Context) (*Conn, error) { dialCtx := ad.ctx @@ -74,11 +73,11 @@ func (ds *dialSync) getActiveDial(p peer.ID) (*activeDial, error) { if !ok { // This code intentionally uses the background context. Otherwise, if the first call // to Dial is canceled, subsequent dial calls will also be canceled. - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancelCause(context.Background()) actd = &activeDial{ - ctx: ctx, - cancel: cancel, - reqch: make(chan dialRequest), + ctx: ctx, + cancelCause: cancel, + reqch: make(chan dialRequest), } go ds.dialWorker(p, actd.reqch) ds.dials[p] = actd @@ -96,14 +95,21 @@ func (ds *dialSync) Dial(ctx context.Context, p peer.ID) (*Conn, error) { return nil, err } - defer func() { - ds.mutex.Lock() - defer ds.mutex.Unlock() - ad.refCnt-- - if ad.refCnt == 0 { - ad.close() - delete(ds.dials, p) + conn, err := ad.dial(ctx) + + ds.mutex.Lock() + defer ds.mutex.Unlock() + + ad.refCnt-- + if ad.refCnt == 0 { + if err == nil { + ad.cancelCause(errConcurrentDialSuccessful) + } else { + ad.cancelCause(err) } - }() - return ad.dial(ctx) + close(ad.reqch) + delete(ds.dials, p) + } + + return conn, err } diff --git a/go-libp2p/p2p/net/swarm/dial_test.go b/go-libp2p/p2p/net/swarm/dial_test.go index 324a985..3b139ef 100644 --- a/go-libp2p/p2p/net/swarm/dial_test.go +++ b/go-libp2p/p2p/net/swarm/dial_test.go @@ -562,7 +562,7 @@ func TestDialSimultaneousJoin(t *testing.T) { return } - t.Logf("first dial succedded; conn: %+v", c) + t.Logf("first dial succeeded; conn: %+v", c) connch <- c errs <- nil @@ -587,7 +587,7 @@ func TestDialSimultaneousJoin(t *testing.T) { return } - t.Logf("second dial succedded; conn: %+v", c) + t.Logf("second dial succeeded; conn: %+v", c) connch <- c errs <- nil @@ -605,7 +605,7 @@ func TestDialSimultaneousJoin(t *testing.T) { return } - t.Logf("third dial succedded; conn: %+v", c) + t.Logf("third dial succeeded; conn: %+v", c) connch <- c errs <- nil @@ -642,3 +642,12 @@ func TestDialSelf(t *testing.T) { _, err := s1.DialPeer(context.Background(), s1.LocalPeer()) require.ErrorIs(t, err, swarm.ErrDialToSelf, "expected error from self dial") } + +func TestDialQUICDraft29(t *testing.T) { + s := makeDialOnlySwarm(t) + id := testutil.RandPeerIDFatal(t) + s.Peerstore().AddAddr(id, ma.StringCast("/ip4/127.0.0.1/udp/1234/quic"), time.Hour) + _, err := s.DialPeer(context.Background(), id) + require.ErrorIs(t, err, swarm.ErrQUICDraft29) + require.ErrorIs(t, err, swarm.ErrNoTransport) +} diff --git a/go-libp2p/p2p/net/swarm/dial_worker.go b/go-libp2p/p2p/net/swarm/dial_worker.go index 0334ac8..0cac6e4 100644 --- a/go-libp2p/p2p/net/swarm/dial_worker.go +++ b/go-libp2p/p2p/net/swarm/dial_worker.go @@ -8,15 +8,12 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + tpt "github.com/libp2p/go-libp2p/core/transport" ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" ) -// ///////////////////////////////////////////////////////////////////////////////// -// lo and behold, The Dialer -// TODO explain how all this works -// //////////////////////////////////////////////////////////////////////////////// - // dialRequest is structure used to request dials to the peer associated with a // worker loop type dialRequest struct { @@ -61,15 +58,14 @@ type addrDial struct { conn *Conn // err is the err on dialing the address err error - // requests is the list of pendRequests interested in this dial - // the value in the slice is the request number assigned to this request by the dialWorker - requests []int // dialed indicates whether we have triggered the dial to the address dialed bool // createdAt is the time this struct was created createdAt time.Time // dialRankingDelay is the delay in dialing this address introduced by the ranking logic dialRankingDelay time.Duration + // expectedTCPUpgradeTime is the expected time by which security upgrade will complete + expectedTCPUpgradeTime time.Time } // dialWorker synchronises concurrent dials to a peer. It ensures that we make at most one dial to a @@ -79,17 +75,13 @@ type dialWorker struct { peer peer.ID // reqch is used to send dial requests to the worker. close reqch to end the worker loop reqch <-chan dialRequest - // reqno is the request number used to track different dialRequests for a peer. - // Each incoming request is assigned a reqno. This reqno is used in pendingRequests and in - // addrDial objects in trackedDials to track this request - reqno int - // pendingRequests maps reqno to the pendRequest object for a dialRequest - pendingRequests map[int]*pendRequest - // trackedDials tracks dials to the peers addresses. An entry here is used to ensure that + // pendingRequests is the set of pendingRequests + pendingRequests map[*pendRequest]struct{} + // trackedDials tracks dials to the peer's addresses. An entry here is used to ensure that // we dial an address at most once trackedDials map[string]*addrDial // resch is used to receive response for dials to the peers addresses. - resch chan dialResult + resch chan tpt.DialUpdate connected bool // true when a connection has been successfully established @@ -106,9 +98,9 @@ func newDialWorker(s *Swarm, p peer.ID, reqch <-chan dialRequest, cl Clock) *dia s: s, peer: p, reqch: reqch, - pendingRequests: make(map[int]*pendRequest), + pendingRequests: make(map[*pendRequest]struct{}), trackedDials: make(map[string]*addrDial), - resch: make(chan dialResult), + resch: make(chan tpt.DialUpdate), cl: cl, } } @@ -128,6 +120,8 @@ func (w *dialWorker) loop() { startTime := w.cl.Now() // dialTimer is the dialTimer used to trigger dials dialTimer := w.cl.InstantTimer(startTime.Add(math.MaxInt64)) + defer dialTimer.Stop() + timerRunning := true // scheduleNextDial updates timer for triggering the next dial scheduleNextDial := func() { @@ -135,12 +129,18 @@ func (w *dialWorker) loop() { <-dialTimer.Ch() } timerRunning = false - if dq.len() > 0 { + if dq.Len() > 0 { if dialsInFlight == 0 && !w.connected { // if there are no dials in flight, trigger the next dials immediately dialTimer.Reset(startTime) } else { - dialTimer.Reset(startTime.Add(dq.top().Delay)) + resetTime := startTime.Add(dq.top().Delay) + for _, ad := range w.trackedDials { + if !ad.expectedTCPUpgradeTime.IsZero() && ad.expectedTCPUpgradeTime.After(resetTime) { + resetTime = ad.expectedTCPUpgradeTime + } + } + dialTimer.Reset(resetTime) } timerRunning = true } @@ -171,15 +171,20 @@ loop: // Enqueue the peer's addresses relevant to this request in dq and // track dials to the addresses relevant to this request. - c, err := w.s.bestAcceptableConnToPeer(req.ctx, w.peer) - if c != nil || err != nil { - req.resch <- dialResponse{conn: c, err: err} + c := w.s.bestAcceptableConnToPeer(req.ctx, w.peer) + if c != nil { + req.resch <- dialResponse{conn: c} continue loop } - addrs, err := w.s.addrsForDial(req.ctx, w.peer) + addrs, addrErrs, err := w.s.addrsForDial(req.ctx, w.peer) if err != nil { - req.resch <- dialResponse{err: err} + req.resch <- dialResponse{ + err: &DialError{ + Peer: w.peer, + DialErrors: addrErrs, + Cause: err, + }} continue loop } @@ -191,8 +196,8 @@ loop: // create the pending request object pr := &pendRequest{ req: req, - err: &DialError{Peer: w.peer}, addrs: make(map[string]struct{}, len(addrRanking)), + err: &DialError{Peer: w.peer, DialErrors: addrErrs}, } for _, adelay := range addrRanking { pr.addrs[string(adelay.Addr.Bytes())] = struct{}{} @@ -233,14 +238,13 @@ loop: if len(todial) == 0 && len(tojoin) == 0 { // all request applicable addrs have been dialed, we must have errored + pr.err.Cause = ErrAllDialsFailed req.resch <- dialResponse{err: pr.err} continue loop } - // The request has some pending or new dials. We assign this request a request number. - // This value of w.reqno is used to track this request in all the structures - w.reqno++ - w.pendingRequests[w.reqno] = pr + // The request has some pending or new dials + w.pendingRequests[pr] = struct{}{} for _, ad := range tojoin { if !ad.dialed { @@ -258,7 +262,6 @@ loop: } } // add the request to the addrDial - ad.requests = append(ad.requests, w.reqno) } if len(todial) > 0 { @@ -268,7 +271,6 @@ loop: w.trackedDials[string(a.Bytes())] = &addrDial{ addr: a, ctx: req.ctx, - requests: []int{w.reqno}, createdAt: now, } dq.Add(network.AddrDelay{Addr: a, Delay: addrDelay[string(a.Bytes())]}) @@ -313,16 +315,29 @@ loop: // Update all requests waiting on this address. On success, complete the request. // On error, record the error - dialsInFlight-- ad, ok := w.trackedDials[string(res.Addr.Bytes())] if !ok { log.Errorf("SWARM BUG: no entry for address %s in trackedDials", res.Addr) if res.Conn != nil { res.Conn.Close() } + dialsInFlight-- continue } + // TCP Connection has been established. Wait for connection upgrade on this address + // before making new dials. + if res.Kind == tpt.UpdateKindHandshakeProgressed { + // Only wait for public addresses to complete dialing since private dials + // are quick any way + if manet.IsPublicAddr(res.Addr) { + ad.expectedTCPUpgradeTime = w.cl.Now().Add(PublicTCPDelay) + } + scheduleNextDial() + continue + } + dialsInFlight-- + ad.expectedTCPUpgradeTime = time.Time{} if res.Conn != nil { // we got a connection, add it to the swarm conn, err := w.s.addConn(res.Conn, network.DirOutbound) @@ -333,20 +348,14 @@ loop: continue loop } - // request succeeded, respond to all pending requests - for _, reqno := range ad.requests { - pr, ok := w.pendingRequests[reqno] - if !ok { - // some other dial for this request succeeded before this one - continue + for pr := range w.pendingRequests { + if _, ok := pr.addrs[string(ad.addr.Bytes())]; ok { + pr.req.resch <- dialResponse{conn: conn} + delete(w.pendingRequests, pr) } - pr.req.resch <- dialResponse{conn: conn} - delete(w.pendingRequests, reqno) } ad.conn = conn - ad.requests = nil - if !w.connected { w.connected = true if w.s.metricsTracer != nil { @@ -380,33 +389,27 @@ loop: // dispatches an error to a specific addr dial func (w *dialWorker) dispatchError(ad *addrDial, err error) { ad.err = err - for _, reqno := range ad.requests { - pr, ok := w.pendingRequests[reqno] - if !ok { - // some other dial for this request succeeded before this one - continue - } - + for pr := range w.pendingRequests { // accumulate the error - pr.err.recordErr(ad.addr, err) - - delete(pr.addrs, string(ad.addr.Bytes())) - if len(pr.addrs) == 0 { - // all addrs have erred, dispatch dial error - // but first do a last one check in case an acceptable connection has landed from - // a simultaneous dial that started later and added new acceptable addrs - c, _ := w.s.bestAcceptableConnToPeer(pr.req.ctx, w.peer) - if c != nil { - pr.req.resch <- dialResponse{conn: c} - } else { - pr.req.resch <- dialResponse{err: pr.err} + if _, ok := pr.addrs[string(ad.addr.Bytes())]; ok { + pr.err.recordErr(ad.addr, err) + delete(pr.addrs, string(ad.addr.Bytes())) + if len(pr.addrs) == 0 { + // all addrs have erred, dispatch dial error + // but first do a last one check in case an acceptable connection has landed from + // a simultaneous dial that started later and added new acceptable addrs + c := w.s.bestAcceptableConnToPeer(pr.req.ctx, w.peer) + if c != nil { + pr.req.resch <- dialResponse{conn: c} + } else { + pr.err.Cause = ErrAllDialsFailed + pr.req.resch <- dialResponse{err: pr.err} + } + delete(w.pendingRequests, pr) } - delete(w.pendingRequests, reqno) } } - ad.requests = nil - // if it was a backoff, clear the address dial so that it doesn't inhibit new dial requests. // this is necessary to support active listen scenarios, where a new dial comes in while // another dial is in progress, and needs to do a direct connection without inhibitions from @@ -439,7 +442,7 @@ func newDialQueue() *dialQueue { // Add adds adelay to the queue. If another element exists in the queue with // the same address, it replaces that element. func (dq *dialQueue) Add(adelay network.AddrDelay) { - for i := 0; i < dq.len(); i++ { + for i := 0; i < dq.Len(); i++ { if dq.q[i].Addr.Equal(adelay.Addr) { if dq.q[i].Delay == adelay.Delay { // existing element is the same. nothing to do @@ -452,7 +455,7 @@ func (dq *dialQueue) Add(adelay network.AddrDelay) { } } - for i := 0; i < dq.len(); i++ { + for i := 0; i < dq.Len(); i++ { if dq.q[i].Delay > adelay.Delay { dq.q = append(dq.q, network.AddrDelay{}) // extend the slice copy(dq.q[i+1:], dq.q[i:]) @@ -465,13 +468,13 @@ func (dq *dialQueue) Add(adelay network.AddrDelay) { // NextBatch returns all the elements in the queue with the highest priority func (dq *dialQueue) NextBatch() []network.AddrDelay { - if dq.len() == 0 { + if dq.Len() == 0 { return nil } // i is the index of the second highest priority element var i int - for i = 0; i < dq.len(); i++ { + for i = 0; i < dq.Len(); i++ { if dq.q[i].Delay != dq.q[0].Delay { break } @@ -486,7 +489,7 @@ func (dq *dialQueue) top() network.AddrDelay { return dq.q[0] } -// len returns the number of elements in the queue -func (dq *dialQueue) len() int { +// Len returns the number of elements in the queue +func (dq *dialQueue) Len() int { return len(dq.q) } diff --git a/go-libp2p/p2p/net/swarm/dial_worker_test.go b/go-libp2p/p2p/net/swarm/dial_worker_test.go index 89130ee..9e9465f 100644 --- a/go-libp2p/p2p/net/swarm/dial_worker_test.go +++ b/go-libp2p/p2p/net/swarm/dial_worker_test.go @@ -26,12 +26,13 @@ import ( "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" - quic "github.com/libp2p/go-libp2p/p2p/transport/quic" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" "github.com/libp2p/go-libp2p/p2p/transport/tcp" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" + "github.com/quic-go/quic-go" "github.com/stretchr/testify/require" ) @@ -61,7 +62,7 @@ func makeSwarm(t *testing.T) *Swarm { t.Fatal(err) } - if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")); err != nil { + if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")); err != nil { t.Fatal(err) } @@ -88,11 +89,11 @@ func makeSwarmWithNoListenAddrs(t *testing.T, opts ...Option) *Swarm { if err := s.AddTransport(tcpTransport); err != nil { t.Fatal(err) } - reuse, err := quicreuse.NewConnManager([32]byte{}) + reuse, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) if err != nil { t.Fatal(err) } - quicTransport, err := quic.NewTransport(priv, reuse, nil, nil, nil) + quicTransport, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -234,7 +235,7 @@ func TestDialWorkerLoopFailure(t *testing.T) { _, p2 := newPeer(t) - s1.Peerstore().AddAddrs(p2, []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic")}, peerstore.PermanentAddrTTL) + s1.Peerstore().AddAddrs(p2, []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic-v1")}, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) resch := make(chan dialResponse) @@ -259,7 +260,7 @@ func TestDialWorkerLoopConcurrentFailure(t *testing.T) { _, p2 := newPeer(t) - s1.Peerstore().AddAddrs(p2, []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic")}, peerstore.PermanentAddrTTL) + s1.Peerstore().AddAddrs(p2, []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic-v1")}, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) worker := newDialWorker(s1, p2, reqch, nil) @@ -307,7 +308,7 @@ func TestDialWorkerLoopConcurrentMix(t *testing.T) { defer s2.Close() s1.Peerstore().AddAddrs(s2.LocalPeer(), s2.ListenAddresses(), peerstore.PermanentAddrTTL) - s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic")}, peerstore.PermanentAddrTTL) + s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{ma.StringCast("/ip4/11.0.0.1/tcp/1234"), ma.StringCast("/ip4/11.0.0.1/udp/1234/quic-v1")}, peerstore.PermanentAddrTTL) reqch := make(chan dialRequest) worker := newDialWorker(s1, s2.LocalPeer(), reqch, nil) @@ -484,8 +485,8 @@ func TestDialQueueNextBatch(t *testing.T) { } } } - if q.len() != 0 { - t.Errorf("expected queue to be empty at end. got: %d", q.len()) + if q.Len() != 0 { + t.Errorf("expected queue to be empty at end. got: %d", q.Len()) } }) } @@ -917,7 +918,7 @@ func TestDialWorkerLoopQuicOverTCP(t *testing.T) { tc := schedulingTestCase{ input: []timedDial{ { - addr: ma.StringCast("/ip4/127.0.0.1/udp/20000/quic"), + addr: ma.StringCast("/ip4/127.0.0.1/udp/20000/quic-v1"), delay: 0, success: true, }, @@ -968,7 +969,7 @@ func TestDialWorkerLoopHolePunching(t *testing.T) { for i := 0; i < len(addrs); i++ { delay := 10 * time.Second if addrs[i].Equal(t1) { - //fire t1 immediately + // fire t1 immediately delay = 0 } else if addrs[i].Equal(t2) { // delay t2 by 100ms @@ -1081,3 +1082,61 @@ func TestDialWorkerLoopAddrDedup(t *testing.T) { t.Errorf("expected a fail response") } } + +func TestDialWorkerLoopTCPConnUpgradeWait(t *testing.T) { + s1 := makeSwarmWithNoListenAddrs(t, WithDialTimeout(10*time.Second)) + s2 := makeSwarmWithNoListenAddrs(t, WithDialTimeout(10*time.Second)) + defer s1.Close() + defer s2.Close() + // Connection to a1 will fail but a1 is a public address so we can test waiting for tcp + // connection established dial update. ipv4only.arpa reserved address. + a1 := ma.StringCast(fmt.Sprintf("/ip4/192.0.0.170/tcp/%d", 10001)) + // Connection to a2 will succeed. + a2 := ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 10002)) + s2.Listen(a2) + + s1.Peerstore().AddAddrs(s2.LocalPeer(), []ma.Multiaddr{a1, a2}, peerstore.PermanentAddrTTL) + + rankerCalled := make(chan struct{}) + s1.dialRanker = func(addrs []ma.Multiaddr) []network.AddrDelay { + defer close(rankerCalled) + return []network.AddrDelay{{Addr: a1, Delay: 0}, {Addr: a2, Delay: 100 * time.Millisecond}} + } + + reqch := make(chan dialRequest) + resch := make(chan dialResponse, 2) + cl := newMockClock() + worker := newDialWorker(s1, s2.LocalPeer(), reqch, cl) + go worker.loop() + defer worker.wg.Wait() + defer close(reqch) + + reqch <- dialRequest{ctx: context.Background(), resch: resch} + + <-rankerCalled + // Wait a bit to let the loop make the dial attempt to a1 + time.Sleep(1 * time.Second) + // Send conn established for a1 + worker.resch <- transport.DialUpdate{Kind: transport.UpdateKindHandshakeProgressed, Addr: a1} + // Dial to a2 shouldn't happen even if a2 is scheduled to dial by now + cl.AdvanceBy(200 * time.Millisecond) + select { + case r := <-resch: + t.Fatalf("didn't expect any event on resch %s %s", r.err, r.conn) + case <-time.After(500 * time.Millisecond): + } + + // Dial to a2 should happen now + // This number is high because there's a race between this goroutine advancing the clock + // and the worker loop goroutine processing the TCPConnectionEstablished event. + // In case it processes the event after the previous clock advancement we need to wait + // 2 * PublicTCPDelay. + cl.AdvanceBy(2 * PublicTCPDelay) + select { + case r := <-resch: + require.NoError(t, r.err) + require.NotNil(t, r.conn) + case <-time.After(3 * time.Second): + t.Errorf("expected a fail response") + } +} diff --git a/go-libp2p/p2p/net/swarm/limiter.go b/go-libp2p/p2p/net/swarm/limiter.go index ccfe7d2..f5638bb 100644 --- a/go-libp2p/p2p/net/swarm/limiter.go +++ b/go-libp2p/p2p/net/swarm/limiter.go @@ -13,17 +13,11 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -type dialResult struct { - Conn transport.CapableConn - Addr ma.Multiaddr - Err error -} - type dialJob struct { addr ma.Multiaddr peer peer.ID ctx context.Context - resp chan dialResult + resp chan transport.DialUpdate timeout time.Duration } @@ -45,7 +39,7 @@ type dialLimiter struct { waitingOnPeerLimit map[peer.ID][]*dialJob } -type dialfunc func(context.Context, peer.ID, ma.Multiaddr) (transport.CapableConn, error) +type dialfunc func(context.Context, peer.ID, ma.Multiaddr, chan<- transport.DialUpdate) (transport.CapableConn, error) func newDialLimiter(df dialfunc) *dialLimiter { fd := ConcurrentFdDials @@ -216,9 +210,13 @@ func (dl *dialLimiter) executeDial(j *dialJob) { dctx, cancel := context.WithTimeout(j.ctx, j.timeout) defer cancel() - con, err := dl.dialFunc(dctx, j.peer, j.addr) + con, err := dl.dialFunc(dctx, j.peer, j.addr, j.resp) + kind := transport.UpdateKindDialSuccessful + if err != nil { + kind = transport.UpdateKindDialFailed + } select { - case j.resp <- dialResult{Conn: con, Addr: j.addr, Err: err}: + case j.resp <- transport.DialUpdate{Kind: kind, Conn: con, Addr: j.addr, Err: err}: case <-j.ctx.Done(): if con != nil { con.Close() diff --git a/go-libp2p/p2p/net/swarm/limiter_test.go b/go-libp2p/p2p/net/swarm/limiter_test.go index 046b4c7..8e61958 100644 --- a/go-libp2p/p2p/net/swarm/limiter_test.go +++ b/go-libp2p/p2p/net/swarm/limiter_test.go @@ -39,7 +39,7 @@ func tcpPortOver(a ma.Multiaddr, n int) bool { return pnum > n } -func tryDialAddrs(ctx context.Context, l *dialLimiter, p peer.ID, addrs []ma.Multiaddr, res chan dialResult) { +func tryDialAddrs(ctx context.Context, l *dialLimiter, p peer.ID, addrs []ma.Multiaddr, res chan transport.DialUpdate) { for _, a := range addrs { l.AddDialJob(&dialJob{ ctx: ctx, @@ -51,7 +51,7 @@ func tryDialAddrs(ctx context.Context, l *dialLimiter, p peer.ID, addrs []ma.Mul } func hangDialFunc(hang chan struct{}) dialfunc { - return func(ctx context.Context, p peer.ID, a ma.Multiaddr) (transport.CapableConn, error) { + return func(ctx context.Context, p peer.ID, a ma.Multiaddr, _ chan<- transport.DialUpdate) (transport.CapableConn, error) { if mafmt.UTP.Matches(a) { return transport.CapableConn(nil), nil } @@ -79,7 +79,7 @@ func TestLimiterBasicDials(t *testing.T) { bads := []ma.Multiaddr{addrWithPort(1), addrWithPort(2), addrWithPort(3), addrWithPort(4)} good := addrWithPort(20) - resch := make(chan dialResult) + resch := make(chan transport.DialUpdate) pid := peer.ID("testpeer") ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -130,7 +130,7 @@ func TestFDLimiting(t *testing.T) { goodTCP := addrWithPort(20) ctx := context.Background() - resch := make(chan dialResult) + resch := make(chan transport.DialUpdate) // take all fd limit tokens with hang dials for _, pid := range pids { @@ -188,7 +188,7 @@ func TestFDLimiting(t *testing.T) { func TestTokenRedistribution(t *testing.T) { var lk sync.Mutex hangchs := make(map[peer.ID]chan struct{}) - df := func(ctx context.Context, p peer.ID, a ma.Multiaddr) (transport.CapableConn, error) { + df := func(ctx context.Context, p peer.ID, a ma.Multiaddr, _ chan<- transport.DialUpdate) (transport.CapableConn, error) { if tcpPortOver(a, 10) { return (transport.CapableConn)(nil), nil } @@ -205,7 +205,7 @@ func TestTokenRedistribution(t *testing.T) { pids := []peer.ID{"testpeer1", "testpeer2"} ctx := context.Background() - resch := make(chan dialResult) + resch := make(chan transport.DialUpdate) // take all fd limit tokens with hang dials for _, pid := range pids { @@ -281,7 +281,7 @@ func TestTokenRedistribution(t *testing.T) { } func TestStressLimiter(t *testing.T) { - df := func(ctx context.Context, p peer.ID, a ma.Multiaddr) (transport.CapableConn, error) { + df := func(ctx context.Context, p peer.ID, a ma.Multiaddr, _ chan<- transport.DialUpdate) (transport.CapableConn, error) { if tcpPortOver(a, 1000) { return transport.CapableConn(nil), nil } @@ -305,7 +305,7 @@ func TestStressLimiter(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - resp := make(chan dialResult) + resp := make(chan transport.DialUpdate) time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) for _, i := range rand.Perm(len(addresses)) { l.AddDialJob(&dialJob{ @@ -335,7 +335,7 @@ func TestStressLimiter(t *testing.T) { } func TestFDLimitUnderflow(t *testing.T) { - df := func(ctx context.Context, p peer.ID, addr ma.Multiaddr) (transport.CapableConn, error) { + df := func(ctx context.Context, p peer.ID, addr ma.Multiaddr, _ chan<- transport.DialUpdate) (transport.CapableConn, error) { select { case <-ctx.Done(): case <-time.After(5 * time.Second): @@ -361,7 +361,7 @@ func TestFDLimitUnderflow(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - resp := make(chan dialResult) + resp := make(chan transport.DialUpdate) l.AddDialJob(&dialJob{ addr: addrs[i], ctx: ctx, diff --git a/go-libp2p/p2p/net/swarm/swarm.go b/go-libp2p/p2p/net/swarm/swarm.go index 5155cd2..7897277 100644 --- a/go-libp2p/p2p/net/swarm/swarm.go +++ b/go-libp2p/p2p/net/swarm/swarm.go @@ -17,6 +17,7 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/transport" + "golang.org/x/exp/slices" logging "github.com/ipfs/go-log/v2" ma "github.com/multiformats/go-multiaddr" @@ -136,8 +137,8 @@ func WithIPv6BlackHoleConfig(enabled bool, n, min int) Option { // communication. The Chan sends/receives Messages, which note the // destination or source Peer. type Swarm struct { - nextConnID uint64 // guarded by atomic - nextStreamID uint64 // guarded by atomic + nextConnID atomic.Uint64 + nextStreamID atomic.Uint64 // Close refcount. This allows us to fully wait for the swarm to be torn // down before continuing. @@ -172,6 +173,11 @@ type Swarm struct { m map[network.Notifiee]struct{} } + directConnNotifs struct { + sync.Mutex + m map[peer.ID][]chan struct{} + } + transports struct { sync.RWMutex m map[int]transport.Transport @@ -197,9 +203,10 @@ type Swarm struct { dialRanker network.DialRanker - udpBlackHoleConfig blackHoleConfig - ipv6BlackHoleConfig blackHoleConfig - bhd *blackHoleDetector + udpBlackHoleConfig blackHoleConfig + ipv6BlackHoleConfig blackHoleConfig + bhd *blackHoleDetector + connectednessEventEmitter *connectednessEventEmitter } // NewSwarm constructs a Swarm. @@ -231,6 +238,8 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts s.listeners.m = make(map[transport.Listener]struct{}) s.transports.m = make(map[int]transport.Transport) s.notifs.m = make(map[network.Notifiee]struct{}) + s.directConnNotifs.m = make(map[peer.ID][]chan struct{}) + s.connectednessEventEmitter = newConnectednessEventEmitter(s.Connectedness, emitter) for _, opt := range opts { if err := opt(s); err != nil { @@ -247,7 +256,6 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts s.backf.init(s.ctx) s.bhd = newBlackHoleDetector(s.udpBlackHoleConfig, s.ipv6BlackHoleConfig, s.metricsTracer) - return s, nil } @@ -256,11 +264,14 @@ func (s *Swarm) Close() error { return nil } +// Done returns a channel that is closed when the swarm is closed. +func (s *Swarm) Done() <-chan struct{} { + return s.ctx.Done() +} + func (s *Swarm) close() { s.ctxCancel() - s.emitter.Close() - // Prevents new connections and/or listeners from being added to the swarm. s.listeners.Lock() listeners := s.listeners.m @@ -274,9 +285,10 @@ func (s *Swarm) close() { // Lots of goroutines but we might as well do this in parallel. We want to shut down as fast as // possible. - + s.refs.Add(len(listeners)) for l := range listeners { go func(l transport.Listener) { + defer s.refs.Done() if err := l.Close(); err != nil && err != transport.ErrListenerClosed { log.Errorf("error when shutting down listener: %s", err) } @@ -295,6 +307,8 @@ func (s *Swarm) close() { // Wait for everything to finish. s.refs.Wait() + s.connectednessEventEmitter.Close() + s.emitter.Close() // Now close out any transports (if necessary). Do this after closing // all connections/listeners. @@ -337,13 +351,14 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, } stat.Direction = dir stat.Opened = time.Now() + isLimited := stat.Limited // Wrap and register the connection. c := &Conn{ conn: tc, swarm: s, stat: stat, - id: atomic.AddUint64(&s.nextConnID, 1), + id: s.nextConnID.Add(1), } // we ONLY check upgraded connections here so we can send them a Disconnect message. @@ -353,7 +368,7 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, // TODO Send disconnect with reason here err := tc.Close() if err != nil { - log.Warnf("failed to close connection with peer %s and addr %s; err: %s", p.Pretty(), addr, err) + log.Warnf("failed to close connection with peer %s and addr %s; err: %s", p, addr, err) } return nil, ErrGaterDisallowedConnection } @@ -377,28 +392,34 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, } c.streams.m = make(map[*Stream]struct{}) - isFirstConnection := len(s.conns.m[p]) == 0 s.conns.m[p] = append(s.conns.m[p], c) - // Add two swarm refs: // * One will be decremented after the close notifications fire in Conn.doClose // * The other will be decremented when Conn.start exits. s.refs.Add(2) - // Take the notification lock before releasing the conns lock to block // Disconnect notifications until after the Connect notifications done. + // This lock also ensures that swarm.refs.Wait() exits after we have + // enqueued the peer connectedness changed notification. + // TODO: Fix this fragility by taking a swarm ref for dial worker loop c.notifyLk.Lock() s.conns.Unlock() - // Emit event after releasing `s.conns` lock so that a consumer can still - // use swarm methods that need the `s.conns` lock. - if isFirstConnection { - s.emitter.Emit(event.EvtPeerConnectednessChanged{ - Peer: p, - Connectedness: network.Connected, - }) - } + s.connectednessEventEmitter.AddConn(p) + if !isLimited { + // Notify goroutines waiting for a direct connection + // + // Go routines interested in waiting for direct connection first acquire this lock + // and then acquire s.conns.RLock. Do not acquire this lock before conns.Unlock to + // prevent deadlock. + s.directConnNotifs.Lock() + for _, ch := range s.directConnNotifs.m[p] { + close(ch) + } + delete(s.directConnNotifs.m, p) + s.directConnNotifs.Unlock() + } s.notifyAll(func(f network.Notifiee) { f.Connected(s, c) }) @@ -429,54 +450,110 @@ func (s *Swarm) StreamHandler() network.StreamHandler { // NewStream creates a new stream on any available connection to peer, dialing // if necessary. +// Use network.WithAllowLimitedConn to open a stream over a limited(relayed) +// connection. func (s *Swarm) NewStream(ctx context.Context, p peer.ID) (network.Stream, error) { log.Debugf("[%s] opening stream to peer [%s]", s.local, p) // Algorithm: // 1. Find the best connection, otherwise, dial. - // 2. Try opening a stream. - // 3. If the underlying connection is, in fact, closed, close the outer + // 2. If the best connection is limited, wait for a direct conn via conn + // reversal or hole punching. + // 3. Try opening a stream. + // 4. If the underlying connection is, in fact, closed, close the outer // connection and try again. We do this in case we have a closed // connection but don't notice it until we actually try to open a // stream. // - // Note: We only dial once. - // // TODO: Try all connections even if we get an error opening a stream on // a non-closed connection. - dials := 0 + numDials := 0 for { - // will prefer direct connections over relayed connections for opening streams - c, err := s.bestAcceptableConnToPeer(ctx, p) - if err != nil { - return nil, err - } - + c := s.bestConnToPeer(p) if c == nil { - if nodial, _ := network.GetNoDial(ctx); nodial { + if nodial, _ := network.GetNoDial(ctx); !nodial { + numDials++ + if numDials > DialAttempts { + return nil, errors.New("max dial attempts exceeded") + } + var err error + c, err = s.dialPeer(ctx, p) + if err != nil { + return nil, err + } + } else { return nil, network.ErrNoConn } + } - if dials >= DialAttempts { - return nil, errors.New("max dial attempts exceeded") - } - dials++ - + limitedAllowed, _ := network.GetAllowLimitedConn(ctx) + if !limitedAllowed && c.Stat().Limited { var err error - c, err = s.dialPeer(ctx, p) + c, err = s.waitForDirectConn(ctx, p) if err != nil { return nil, err } } - s, err := c.NewStream(ctx) + str, err := c.NewStream(ctx) if err != nil { if c.conn.IsClosed() { continue } return nil, err } - return s, nil + return str, nil + } +} + +// waitForDirectConn waits for a direct connection established through hole punching or connection reversal. +func (s *Swarm) waitForDirectConn(ctx context.Context, p peer.ID) (*Conn, error) { + s.directConnNotifs.Lock() + c := s.bestConnToPeer(p) + if c == nil { + s.directConnNotifs.Unlock() + return nil, network.ErrNoConn + } else if !c.Stat().Limited { + s.directConnNotifs.Unlock() + return c, nil + } + + // Wait for limited connection to upgrade to a direct connection either by + // connection reversal or hole punching. + ch := make(chan struct{}) + s.directConnNotifs.m[p] = append(s.directConnNotifs.m[p], ch) + s.directConnNotifs.Unlock() + + // apply the DialPeer timeout + ctx, cancel := context.WithTimeout(ctx, network.GetDialPeerTimeout(ctx)) + defer cancel() + + // Wait for notification. + select { + case <-ctx.Done(): + // Remove ourselves from the notification list + s.directConnNotifs.Lock() + defer s.directConnNotifs.Unlock() + + s.directConnNotifs.m[p] = slices.DeleteFunc( + s.directConnNotifs.m[p], + func(c chan struct{}) bool { return c == ch }, + ) + if len(s.directConnNotifs.m[p]) == 0 { + delete(s.directConnNotifs.m, p) + } + return nil, ctx.Err() + case <-ch: + // We do not need to remove ourselves from the list here as the notifier + // clears the map entry + c := s.bestConnToPeer(p) + if c == nil { + return nil, network.ErrNoConn + } + if c.Stat().Limited { + return nil, network.ErrLimitedConn + } + return c, nil } } @@ -495,11 +572,11 @@ func (s *Swarm) ConnsToPeer(p peer.ID) []network.Conn { } func isBetterConn(a, b *Conn) bool { - // If one is transient and not the other, prefer the non-transient connection. - aTransient := a.Stat().Transient - bTransient := b.Stat().Transient - if aTransient != bTransient { - return !aTransient + // If one is limited and not the other, prefer the unlimited connection. + aLimited := a.Stat().Limited + bLimited := b.Stat().Limited + if aLimited != bLimited { + return !aLimited } // If one is direct and not the other, prefer the direct connection. @@ -548,26 +625,17 @@ func (s *Swarm) bestConnToPeer(p peer.ID) *Conn { return best } -// - Returns the best "acceptable" connection, if available. -// - Returns nothing if no such connection exists, but if we should try dialing anyways. -// - Returns an error if no such connection exists, but we should not try dialing. -func (s *Swarm) bestAcceptableConnToPeer(ctx context.Context, p peer.ID) (*Conn, error) { +// bestAcceptableConnToPeer returns the best acceptable connection, considering the passed in ctx. +// If network.WithForceDirectDial is used, it only returns a direct connections, ignoring +// any limited (relayed) connections to the peer. +func (s *Swarm) bestAcceptableConnToPeer(ctx context.Context, p peer.ID) *Conn { conn := s.bestConnToPeer(p) - if conn == nil { - return nil, nil - } forceDirect, _ := network.GetForceDirectDial(ctx) if forceDirect && !isDirectConn(conn) { - return nil, nil + return nil } - - useTransient, _ := network.GetUseTransient(ctx) - if useTransient || !conn.Stat().Transient { - return conn, nil - } - - return nil, network.ErrTransientConn + return conn } func isDirectConn(c *Conn) bool { @@ -579,8 +647,28 @@ func isDirectConn(c *Conn) bool { // To check if we have an open connection, use `s.Connectedness(p) == // network.Connected`. func (s *Swarm) Connectedness(p peer.ID) network.Connectedness { - if s.bestConnToPeer(p) != nil { - return network.Connected + s.conns.RLock() + defer s.conns.RUnlock() + + return s.connectednessUnlocked(p) +} + +// connectednessUnlocked returns the connectedness of a peer. +func (s *Swarm) connectednessUnlocked(p peer.ID) network.Connectedness { + var haveLimited bool + for _, c := range s.conns.m[p] { + if c.IsClosed() { + // These will be garbage collected soon + continue + } + if c.Stat().Limited { + haveLimited = true + } else { + return network.Connected + } + } + if haveLimited { + return network.Limited } return network.NotConnected } @@ -678,24 +766,7 @@ func (s *Swarm) removeConn(c *Conn) { p := c.RemotePeer() s.conns.Lock() - cs := s.conns.m[p] - - if len(cs) == 1 { - delete(s.conns.m, p) - s.conns.Unlock() - - // Emit event after releasing `s.conns` lock so that a consumer can still - // use swarm methods that need the `s.conns` lock. - s.emitter.Emit(event.EvtPeerConnectednessChanged{ - Peer: p, - Connectedness: network.NotConnected, - }) - return - } - - defer s.conns.Unlock() - for i, ci := range cs { if ci == c { // NOTE: We're intentionally preserving order. @@ -707,6 +778,10 @@ func (s *Swarm) removeConn(c *Conn) { break } } + if len(s.conns.m[p]) == 0 { + delete(s.conns.m, p) + } + s.conns.Unlock() } // String returns a string representation of Network. diff --git a/go-libp2p/p2p/net/swarm/swarm_addr_test.go b/go-libp2p/p2p/net/swarm/swarm_addr_test.go index 6cb4f96..435866e 100644 --- a/go-libp2p/p2p/net/swarm/swarm_addr_test.go +++ b/go-libp2p/p2p/net/swarm/swarm_addr_test.go @@ -2,6 +2,7 @@ package swarm_test import ( "context" + "crypto/sha256" "fmt" "testing" @@ -13,15 +14,15 @@ import ( "github.com/libp2p/go-libp2p/p2p/net/swarm" swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" circuitv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" - quic "github.com/libp2p/go-libp2p/p2p/transport/quic" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" "github.com/libp2p/go-libp2p/p2p/transport/tcp" webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" - "github.com/minio/sha256-simd" ma "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multibase" "github.com/multiformats/go-multihash" + "github.com/quic-go/quic-go" "github.com/stretchr/testify/require" ) @@ -81,10 +82,10 @@ func TestDialAddressSelection(t *testing.T) { tcpTr, err := tcp.NewTCPTransport(nil, nil) require.NoError(t, err) require.NoError(t, s.AddTransport(tcpTr)) - reuse, err := quicreuse.NewConnManager([32]byte{}) + reuse, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) require.NoError(t, err) defer reuse.Close() - quicTr, err := quic.NewTransport(priv, reuse, nil, nil, nil) + quicTr, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) require.NoError(t, err) require.NoError(t, s.AddTransport(quicTr)) webtransportTr, err := webtransport.New(priv, nil, reuse, nil, nil) @@ -100,7 +101,7 @@ func TestDialAddressSelection(t *testing.T) { require.NoError(t, s.AddTransport(circuitTr)) require.Equal(t, tcpTr, s.TransportForDialing(ma.StringCast("/ip4/127.0.0.1/tcp/1234"))) - require.Equal(t, quicTr, s.TransportForDialing(ma.StringCast("/ip4/127.0.0.1/udp/1234/quic"))) + require.Equal(t, quicTr, s.TransportForDialing(ma.StringCast("/ip4/127.0.0.1/udp/1234/quic-v1"))) require.Equal(t, circuitTr, s.TransportForDialing(ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/udp/1234/quic/p2p-circuit/p2p/%s", id)))) require.Equal(t, webtransportTr, s.TransportForDialing(ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/%s", certHash)))) require.Nil(t, s.TransportForDialing(ma.StringCast("/ip4/1.2.3.4"))) diff --git a/go-libp2p/p2p/net/swarm/swarm_conn.go b/go-libp2p/p2p/net/swarm/swarm_conn.go index e770381..38e942c 100644 --- a/go-libp2p/p2p/net/swarm/swarm_conn.go +++ b/go-libp2p/p2p/net/swarm/swarm_conn.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "sync" - "sync/atomic" "time" ic "github.com/libp2p/go-libp2p/core/crypto" @@ -49,7 +48,7 @@ func (c *Conn) IsClosed() bool { func (c *Conn) ID() string { // format: - - return fmt.Sprintf("%s-%d", c.RemotePeer().Pretty()[0:10], c.id) + return fmt.Sprintf("%s-%d", c.RemotePeer().String()[:10], c.id) } // Close closes this connection. @@ -74,6 +73,11 @@ func (c *Conn) doClose() { c.err = c.conn.Close() + // Send the connectedness event after closing the connection. + // This ensures that both remote connection close and local connection + // close events are sent after the underlying transport connection is closed. + c.swarm.connectednessEventEmitter.RemoveConn(c.RemotePeer()) + // This is just for cleaning up state. The connection has already been closed. // We *could* optimize this but it really isn't worth it. for s := range streams { @@ -86,10 +90,11 @@ func (c *Conn) doClose() { c.notifyLk.Lock() defer c.notifyLk.Unlock() + // Only notify for disconnection if we notified for connection c.swarm.notifyAll(func(f network.Notifiee) { f.Disconnected(c.swarm, c) }) - c.swarm.refs.Done() // taken in Swarm.addConn + c.swarm.refs.Done() }() } @@ -109,7 +114,6 @@ func (c *Conn) start() { go func() { defer c.swarm.refs.Done() defer c.Close() - for { ts, err := c.conn.AcceptStream() if err != nil { @@ -137,6 +141,7 @@ func (c *Conn) start() { if h := c.swarm.StreamHandler(); h != nil { h(s) } + s.completeAcceptStreamGoroutine() }() } }() @@ -147,9 +152,9 @@ func (c *Conn) String() string { " %s (%s)>", c.conn.Transport(), c.conn.LocalMultiaddr(), - c.conn.LocalPeer().Pretty(), + c.conn.LocalPeer(), c.conn.RemoteMultiaddr(), - c.conn.RemotePeer().Pretty(), + c.conn.RemotePeer(), ) } @@ -193,9 +198,9 @@ func (c *Conn) Stat() network.ConnStats { // NewStream returns a new Stream from this connection func (c *Conn) NewStream(ctx context.Context) (network.Stream, error) { - if c.Stat().Transient { - if useTransient, _ := network.GetUseTransient(ctx); !useTransient { - return nil, network.ErrTransientConn + if c.Stat().Limited { + if useLimited, _ := network.GetAllowLimitedConn(ctx); !useLimited { + return nil, network.ErrLimitedConn } } @@ -238,7 +243,8 @@ func (c *Conn) addStream(ts network.MuxedStream, dir network.Direction, scope ne Direction: dir, Opened: time.Now(), }, - id: atomic.AddUint64(&c.swarm.nextStreamID, 1), + id: c.swarm.nextStreamID.Add(1), + acceptStreamGoroutineCompleted: dir != network.DirInbound, } c.stat.NumStreams++ c.streams.m[s] = struct{}{} diff --git a/go-libp2p/p2p/net/swarm/swarm_dial.go b/go-libp2p/p2p/net/swarm/swarm_dial.go index f2df93a..f639ce1 100644 --- a/go-libp2p/p2p/net/swarm/swarm_dial.go +++ b/go-libp2p/p2p/net/swarm/swarm_dial.go @@ -14,8 +14,10 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/transport" + ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" + mafmt "github.com/multiformats/go-multiaddr-fmt" manet "github.com/multiformats/go-multiaddr/net" ) @@ -65,6 +67,19 @@ var ( ErrGaterDisallowedConnection = errors.New("gater disallows connection to peer") ) +// ErrQUICDraft29 wraps ErrNoTransport and provide a more meaningful error message +var ErrQUICDraft29 errQUICDraft29 + +type errQUICDraft29 struct{} + +func (errQUICDraft29) Error() string { + return "QUIC draft-29 has been removed, QUIC (RFC 9000) is accessible with /quic-v1" +} + +func (errQUICDraft29) Unwrap() error { + return ErrNoTransport +} + // DialAttempts governs how many times a goroutine will try to dial a given peer. // Note: this is down to one, as we have _too many dials_ atm. To add back in, // add loop back in Dial(.) @@ -201,7 +216,8 @@ func (db *DialBackoff) cleanup() { } } -// DialPeer connects to a peer. +// DialPeer connects to a peer. Use network.WithForceDirectDial to force a +// direct connection. // // The idea is that the client of Swarm does not need to know what network // the connection will happen over. Swarm can use whichever it choses. @@ -231,15 +247,14 @@ func (s *Swarm) dialPeer(ctx context.Context, p peer.ID) (*Conn, error) { return nil, ErrDialToSelf } - // check if we already have an open (usable) connection first, or can't have a usable - // connection. - conn, err := s.bestAcceptableConnToPeer(ctx, p) - if conn != nil || err != nil { - return conn, err + // check if we already have an open (usable) connection. + conn := s.bestAcceptableConnToPeer(ctx, p) + if conn != nil { + return conn, nil } if s.gater != nil && !s.gater.InterceptPeerDial(p) { - log.Debugf("gater disallowed outbound connection to peer %s", p.Pretty()) + log.Debugf("gater disallowed outbound connection to peer %s", p) return nil, &DialError{Peer: p, Cause: ErrGaterDisallowedConnection} } @@ -280,68 +295,47 @@ func (s *Swarm) dialWorkerLoop(p peer.ID, reqch <-chan dialRequest) { w.loop() } -func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) ([]ma.Multiaddr, error) { +func (s *Swarm) addrsForDial(ctx context.Context, p peer.ID) (goodAddrs []ma.Multiaddr, addrErrs []TransportError, err error) { peerAddrs := s.peers.Addrs(p) if len(peerAddrs) == 0 { - return nil, ErrNoAddresses - } - - peerAddrsAfterTransportResolved := make([]ma.Multiaddr, 0, len(peerAddrs)) - for _, a := range peerAddrs { - tpt := s.TransportForDialing(a) - resolver, ok := tpt.(transport.Resolver) - if ok { - resolvedAddrs, err := resolver.Resolve(ctx, a) - if err != nil { - log.Warnf("Failed to resolve multiaddr %s by transport %v: %v", a, tpt, err) - continue - } - peerAddrsAfterTransportResolved = append(peerAddrsAfterTransportResolved, resolvedAddrs...) - } else { - peerAddrsAfterTransportResolved = append(peerAddrsAfterTransportResolved, a) - } + return nil, nil, ErrNoAddresses } // Resolve dns or dnsaddrs - resolved, err := s.resolveAddrs(ctx, peer.AddrInfo{ - ID: p, - Addrs: peerAddrsAfterTransportResolved, - }) + resolved, err := s.resolveAddrs(ctx, peer.AddrInfo{ID: p, Addrs: peerAddrs}) if err != nil { - return nil, err + return nil, nil, err } - goodAddrs := s.filterKnownUndialables(p, resolved) + goodAddrs = ma.Unique(resolved) + goodAddrs, addrErrs = s.filterKnownUndialables(p, goodAddrs) if forceDirect, _ := network.GetForceDirectDial(ctx); forceDirect { goodAddrs = ma.FilterAddrs(goodAddrs, s.nonProxyAddr) } - goodAddrs = ma.Unique(goodAddrs) if len(goodAddrs) == 0 { - return nil, ErrNoGoodAddresses + return nil, addrErrs, ErrNoGoodAddresses } s.peers.AddAddrs(p, goodAddrs, peerstore.TempAddrTTL) - return goodAddrs, nil + return goodAddrs, addrErrs, nil } func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multiaddr, error) { - proto := ma.ProtocolWithCode(ma.P_P2P).Name - p2paddr, err := ma.NewMultiaddr("/" + proto + "/" + pi.ID.Pretty()) + p2paddr, err := ma.NewMultiaddr("/" + ma.ProtocolWithCode(ma.P_P2P).Name + "/" + pi.ID.String()) if err != nil { return nil, err } - resolveSteps := 0 - + var resolveSteps int // Recursively resolve all addrs. // // While the toResolve list is non-empty: // * Pop an address off. // * If the address is fully resolved, add it to the resolved list. // * Otherwise, resolve it and add the results to the "to resolve" list. - toResolve := append(([]ma.Multiaddr)(nil), pi.Addrs...) + toResolve := append([]ma.Multiaddr{}, pi.Addrs...) resolved := make([]ma.Multiaddr, 0, len(pi.Addrs)) for len(toResolve) > 0 { // pop the last addr off. @@ -368,6 +362,26 @@ func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multia continue } + tpt := s.TransportForDialing(addr) + resolver, ok := tpt.(transport.Resolver) + if ok { + resolvedAddrs, err := resolver.Resolve(ctx, addr) + if err != nil { + log.Warnf("Failed to resolve multiaddr %s by transport %v: %v", addr, tpt, err) + continue + } + var added bool + for _, a := range resolvedAddrs { + if !addr.Equal(a) { + toResolve = append(toResolve, a) + added = true + } + } + if added { + continue + } + } + // otherwise, resolve it reqaddr := addr.Encapsulate(p2paddr) resaddrs, err := s.maResolver.Resolve(ctx, reqaddr) @@ -388,7 +402,7 @@ func (s *Swarm) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Multia return resolved, nil } -func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, resch chan dialResult) error { +func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, resch chan transport.DialUpdate) error { // check the dial backoff if forceDirect, _ := network.GetForceDirectDial(ctx); !forceDirect { if s.backf.Backoff(p, addr) { @@ -402,23 +416,20 @@ func (s *Swarm) dialNextAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, return nil } -func (s *Swarm) canDial(addr ma.Multiaddr) bool { - t := s.TransportForDialing(addr) - return t != nil && t.CanDial(addr) -} - func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool { t := s.TransportForDialing(addr) return !t.Proxy() } +var quicDraft29DialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC)) + // filterKnownUndialables takes a list of multiaddrs, and removes those // that we definitely don't want to dial: addresses configured to be blocked, // IPv6 link-local addresses, addresses without a dial-capable transport, -// addresses that we know to be our own, and addresses with a better tranport +// addresses that we know to be our own, and addresses with a better transport // available. This is an optimization to avoid wasting time on dials that we // know are going to fail or for which we have a better alternative. -func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) []ma.Multiaddr { +func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAddrs []ma.Multiaddr, addrErrs []TransportError) { lisAddrs, _ := s.InterfaceListenAddresses() var ourAddrs []ma.Multiaddr for _, addr := range lisAddrs { @@ -431,35 +442,71 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) []ma.Mul }) } - // The order of these two filters is important. If we can only dial /webtransport, - // we don't want to filter /webtransport addresses out because the peer had a /quic-v1 - // address + addrErrs = make([]TransportError, 0, len(addrs)) - // filter addresses we cannot dial - addrs = ma.FilterAddrs(addrs, s.canDial) + // The order of checking for transport and filtering low priority addrs is important. If we + // can only dial /webtransport, we don't want to filter /webtransport addresses out because + // the peer had a /quic-v1 address + + // filter addresses with no transport + addrs = ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool { + if s.TransportForDialing(a) == nil { + e := ErrNoTransport + // We used to support QUIC draft-29 for a long time. + // Provide a more useful error when attempting to dial a QUIC draft-29 address. + if quicDraft29DialMatcher.Matches(a) { + e = ErrQUICDraft29 + } + addrErrs = append(addrErrs, TransportError{Address: a, Cause: e}) + return false + } + return true + }) // filter low priority addresses among the addresses we can dial + // We don't return an error for these addresses addrs = filterLowPriorityAddresses(addrs) // remove black holed addrs - addrs = s.bhd.FilterAddrs(addrs) + addrs, blackHoledAddrs := s.bhd.FilterAddrs(addrs) + for _, a := range blackHoledAddrs { + addrErrs = append(addrErrs, TransportError{Address: a, Cause: ErrDialRefusedBlackHole}) + } return ma.FilterAddrs(addrs, - func(addr ma.Multiaddr) bool { return !ma.Contains(ourAddrs, addr) }, + // Linux and BSD treat an unspecified address when dialing as a localhost address. + // Windows doesn't support this. We filter all such addresses out because peers + // listening on unspecified addresses will advertise more specific addresses. + // https://unix.stackexchange.com/a/419881 + // https://superuser.com/a/1755455 + func(addr ma.Multiaddr) bool { + return !manet.IsIPUnspecified(addr) + }, + func(addr ma.Multiaddr) bool { + if ma.Contains(ourAddrs, addr) { + addrErrs = append(addrErrs, TransportError{Address: addr, Cause: ErrDialToSelf}) + return false + } + return true + }, // TODO: Consider allowing link-local addresses func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) }, func(addr ma.Multiaddr) bool { - return s.gater == nil || s.gater.InterceptAddrDial(p, addr) + if s.gater != nil && !s.gater.InterceptAddrDial(p, addr) { + addrErrs = append(addrErrs, TransportError{Address: addr, Cause: ErrGaterDisallowedConnection}) + return false + } + return true }, - ) + ), addrErrs } // limitedDial will start a dial to the given peer when // it is able, respecting the various different types of rate // limiting that occur without using extra goroutines per addr -func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp chan dialResult) { +func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp chan transport.DialUpdate) { timeout := s.dialTimeout - if lowTimeoutFilters.AddrBlocked(a) && s.dialTimeoutLocal < s.dialTimeout { + if manet.IsPrivateAddr(a) && s.dialTimeoutLocal < s.dialTimeout { timeout = s.dialTimeoutLocal } s.limiter.AddDialJob(&dialJob{ @@ -472,7 +519,7 @@ func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp } // dialAddr is the actual dial for an addr, indirectly invoked through the limiter -func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (transport.CapableConn, error) { +func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr, updCh chan<- transport.DialUpdate) (transport.CapableConn, error) { // Just to double check. Costs nothing. if s.local == p { return nil, ErrDialToSelf @@ -490,16 +537,22 @@ func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (tra } start := time.Now() - connC, err := tpt.Dial(ctx, addr, p) + var connC transport.CapableConn + var err error + if du, ok := tpt.(transport.DialUpdater); ok { + connC, err = du.DialWithUpdates(ctx, addr, p, updCh) + } else { + connC, err = tpt.Dial(ctx, addr, p) + } // We're recording any error as a failure here. - // Notably, this also applies to cancelations (i.e. if another dial attempt was faster). + // Notably, this also applies to cancellations (i.e. if another dial attempt was faster). // This is ok since the black hole detector uses a very low threshold (5%). s.bhd.RecordResult(addr, err == nil) if err != nil { if s.metricsTracer != nil { - s.metricsTracer.FailedDialing(addr, err) + s.metricsTracer.FailedDialing(addr, err, context.Cause(ctx)) } return nil, err } diff --git a/go-libp2p/p2p/net/swarm/swarm_dial_test.go b/go-libp2p/p2p/net/swarm/swarm_dial_test.go index 2f6b3f8..83f94b9 100644 --- a/go-libp2p/p2p/net/swarm/swarm_dial_test.go +++ b/go-libp2p/p2p/net/swarm/swarm_dial_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/rand" + "errors" "net" "sort" "testing" @@ -65,7 +66,7 @@ func TestAddrsForDial(t *testing.T) { ps.AddAddr(otherPeer, ma.StringCast("/dns4/example.com/tcp/1234/wss"), time.Hour) ctx := context.Background() - mas, err := s.addrsForDial(ctx, otherPeer) + mas, _, err := s.addrsForDial(ctx, otherPeer) require.NoError(t, err) require.NotZero(t, len(mas)) @@ -110,10 +111,10 @@ func TestDedupAddrsForDial(t *testing.T) { ps.AddAddr(otherPeer, ma.StringCast("/ip4/1.2.3.4/tcp/1234"), time.Hour) ctx := context.Background() - mas, err := s.addrsForDial(ctx, otherPeer) + mas, _, err := s.addrsForDial(ctx, otherPeer) require.NoError(t, err) - require.Equal(t, 1, len(mas)) + require.Len(t, mas, 1) } func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm { @@ -138,7 +139,7 @@ func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm { err = s.AddTransport(tpt) require.NoError(t, err) - connmgr, err := quicreuse.NewConnManager(quic.StatelessResetKey{}) + connmgr, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) require.NoError(t, err) quicTpt, err := libp2pquic.NewTransport(priv, connmgr, nil, nil, &network.NullResourceManager{}) require.NoError(t, err) @@ -166,8 +167,8 @@ func TestAddrResolution(t *testing.T) { addr1 := ma.StringCast("/dnsaddr/example.com") addr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123") - p2paddr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.Pretty()) - p2paddr3 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p2.Pretty()) + p2paddr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.String()) + p2paddr3 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p2.String()) backend := &madns.MockResolver{ TXT: map[string][]string{"_dnsaddr.example.com": { @@ -183,7 +184,7 @@ func TestAddrResolution(t *testing.T) { tctx, cancel := context.WithTimeout(ctx, time.Millisecond*100) defer cancel() - mas, err := s.addrsForDial(tctx, p1) + mas, _, err := s.addrsForDial(tctx, p1) require.NoError(t, err) require.Len(t, mas, 1) @@ -196,23 +197,16 @@ func TestAddrResolution(t *testing.T) { } func TestAddrResolutionRecursive(t *testing.T) { - ctx := context.Background() + p1 := test.RandPeerIDFatal(t) + p2 := test.RandPeerIDFatal(t) - p1, err := test.RandPeerID() - if err != nil { - t.Error(err) - } - p2, err := test.RandPeerID() - if err != nil { - t.Error(err) - } addr1 := ma.StringCast("/dnsaddr/example.com") addr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123") - p2paddr1 := ma.StringCast("/dnsaddr/example.com/p2p/" + p1.Pretty()) - p2paddr2 := ma.StringCast("/dnsaddr/example.com/p2p/" + p2.Pretty()) - p2paddr1i := ma.StringCast("/dnsaddr/foo.example.com/p2p/" + p1.Pretty()) - p2paddr2i := ma.StringCast("/dnsaddr/bar.example.com/p2p/" + p2.Pretty()) - p2paddr1f := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.Pretty()) + p2paddr1 := ma.StringCast("/dnsaddr/example.com/p2p/" + p1.String()) + p2paddr2 := ma.StringCast("/dnsaddr/example.com/p2p/" + p2.String()) + p2paddr1i := ma.StringCast("/dnsaddr/foo.example.com/p2p/" + p1.String()) + p2paddr2i := ma.StringCast("/dnsaddr/bar.example.com/p2p/" + p2.String()) + p2paddr1f := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.String()) backend := &madns.MockResolver{ TXT: map[string][]string{ @@ -220,28 +214,22 @@ func TestAddrResolutionRecursive(t *testing.T) { "dnsaddr=" + p2paddr1i.String(), "dnsaddr=" + p2paddr2i.String(), }, - "_dnsaddr.foo.example.com": { - "dnsaddr=" + p2paddr1f.String(), - }, - "_dnsaddr.bar.example.com": { - "dnsaddr=" + p2paddr2i.String(), - }, + "_dnsaddr.foo.example.com": {"dnsaddr=" + p2paddr1f.String()}, + "_dnsaddr.bar.example.com": {"dnsaddr=" + p2paddr2i.String()}, }, } resolver, err := madns.NewResolver(madns.WithDefaultResolver(backend)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) s := newTestSwarmWithResolver(t, resolver) pi1, err := peer.AddrInfoFromP2pAddr(p2paddr1) require.NoError(t, err) - tctx, cancel := context.WithTimeout(ctx, time.Millisecond*100) + tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) defer cancel() s.Peerstore().AddAddrs(pi1.ID, pi1.Addrs, peerstore.TempAddrTTL) - _, err = s.addrsForDial(tctx, p1) + _, _, err = s.addrsForDial(tctx, p1) require.NoError(t, err) addrs1 := s.Peerstore().Addrs(pi1.ID) @@ -253,7 +241,7 @@ func TestAddrResolutionRecursive(t *testing.T) { require.NoError(t, err) s.Peerstore().AddAddrs(pi2.ID, pi2.Addrs, peerstore.TempAddrTTL) - _, err = s.addrsForDial(tctx, p2) + _, _, err = s.addrsForDial(tctx, p2) // This never resolves to a good address require.Equal(t, ErrNoGoodAddresses, err) @@ -262,20 +250,51 @@ func TestAddrResolutionRecursive(t *testing.T) { require.Contains(t, addrs2, addr1) } +// see https://github.com/libp2p/go-libp2p/issues/2562 +func TestAddrResolutionRecursiveTransportSpecific(t *testing.T) { + p := test.RandPeerIDFatal(t) + + backend := &madns.MockResolver{ + IP: map[string][]net.IPAddr{ + "sub.example.com": {net.IPAddr{IP: net.IPv4(1, 2, 3, 4)}}, + }, + TXT: map[string][]string{ + "_dnsaddr.example.com": {"dnsaddr=/dns4/sub.example.com/tcp/443/wss/p2p/" + p.String()}, + }, + } + resolver, err := madns.NewResolver(madns.WithDefaultResolver(backend)) + require.NoError(t, err) + + s := newTestSwarmWithResolver(t, resolver) + pi1, err := peer.AddrInfoFromP2pAddr(ma.StringCast("/dnsaddr/example.com/p2p/" + p.String())) + require.NoError(t, err) + + tctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) + defer cancel() + s.Peerstore().AddAddrs(pi1.ID, pi1.Addrs, peerstore.TempAddrTTL) + addrs, _, err := s.addrsForDial(tctx, p) + require.NoError(t, err) + require.Len(t, addrs, 1) + require.Equal(t, "/ip4/1.2.3.4/tcp/443/tls/sni/sub.example.com/ws", addrs[0].String()) +} + func TestAddrsForDialFiltering(t *testing.T) { - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") + q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") wt2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1/webtransport/") - q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic") + q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1") ws1 := ma.StringCast("/ip4/1.2.3.4/tcp/1/ws") + unSpecQ := ma.StringCast("/ip4/0.0.0.0/udp/2/quic-v1") + unSpecT := ma.StringCast("/ip6/::/tcp/2/") + resolver, err := madns.NewResolver(madns.WithDefaultResolver(&madns.MockResolver{})) require.NoError(t, err) s := newTestSwarmWithResolver(t, resolver) @@ -306,6 +325,11 @@ func TestAddrsForDialFiltering(t *testing.T) { input: append([]ma.Multiaddr{q1}, ourAddrs...), output: []ma.Multiaddr{q1}, }, + { + name: "unspecified-filtered", + input: []ma.Multiaddr{q1v1, t1, unSpecQ, unSpecT}, + output: []ma.Multiaddr{q1v1, t1}, + }, } ctx := context.Background() @@ -315,7 +339,7 @@ func TestAddrsForDialFiltering(t *testing.T) { t.Run(tc.name, func(t *testing.T) { s.Peerstore().ClearAddrs(p1) s.Peerstore().AddAddrs(p1, tc.input, peerstore.PermanentAddrTTL) - result, err := s.addrsForDial(ctx, p1) + result, _, err := s.addrsForDial(ctx, p1) require.NoError(t, err) sort.Slice(result, func(i, j int) bool { return bytes.Compare(result[i].Bytes(), result[j].Bytes()) < 0 }) sort.Slice(tc.output, func(i, j int) bool { return bytes.Compare(tc.output[i].Bytes(), tc.output[j].Bytes()) < 0 }) @@ -342,8 +366,9 @@ func TestBlackHoledAddrBlocked(t *testing.T) { n := 3 s.bhd.ipv6 = &blackHoleFilter{n: n, minSuccesses: 1, name: "IPv6"} - // all dials to the address will fail. RFC6666 Discard Prefix - addr := ma.StringCast("/ip6/0100::1/tcp/54321/") + // All dials to this addr will fail. + // manet.IsPublic is aggressive for IPv6 addresses. Use a NAT64 address. + addr := ma.StringCast("/ip6/64:ff9b::1.2.3.4/tcp/54321/") p, err := test.RandPeerID() if err != nil { @@ -366,10 +391,10 @@ func TestBlackHoledAddrBlocked(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() conn, err := s.DialPeer(ctx, p) - if conn != nil { - t.Fatalf("expected dial to be blocked") - } - if err != ErrNoGoodAddresses { + require.Nil(t, conn) + var de *DialError + if !errors.As(err, &de) { t.Fatalf("expected to receive an error of type *DialError, got %s of type %T", err, err) } + require.ErrorIs(t, err, ErrDialRefusedBlackHole) } diff --git a/go-libp2p/p2p/net/swarm/swarm_event_test.go b/go-libp2p/p2p/net/swarm/swarm_event_test.go index 86d698d..5010215 100644 --- a/go-libp2p/p2p/net/swarm/swarm_event_test.go +++ b/go-libp2p/p2p/net/swarm/swarm_event_test.go @@ -2,6 +2,7 @@ package swarm_test import ( "context" + "sync" "testing" "time" @@ -12,6 +13,7 @@ import ( swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -66,6 +68,10 @@ func TestConnectednessEventsSingleConn(t *testing.T) { } func TestNoDeadlockWhenConsumingConnectednessEvents(t *testing.T) { + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + dialerEventBus := eventbus.NewBus() dialer := swarmt.GenSwarm(t, swarmt.OptDialOnly, swarmt.EventBus(dialerEventBus)) defer dialer.Close() @@ -85,10 +91,6 @@ func TestNoDeadlockWhenConsumingConnectednessEvents(t *testing.T) { sub, err := dialerEventBus.Subscribe(new(event.EvtPeerConnectednessChanged)) require.NoError(t, err) - ctx := context.Background() - ctx, cancel := context.WithCancel(ctx) - defer cancel() - // A slow consumer go func() { for { @@ -113,3 +115,196 @@ func TestNoDeadlockWhenConsumingConnectednessEvents(t *testing.T) { // The test should finish without deadlocking } + +func TestConnectednessEvents(t *testing.T) { + s1, sub1 := newSwarmWithSubscription(t) + const N = 100 + peers := make([]*Swarm, N) + for i := 0; i < N; i++ { + peers[i] = swarmt.GenSwarm(t) + } + + // First check all connected events + done := make(chan struct{}) + go func() { + defer close(done) + for i := 0; i < N; i++ { + e := <-sub1.Out() + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Error("invalid event received", e) + return + } + if evt.Connectedness != network.Connected { + t.Errorf("invalid event received: expected: Connected, got: %s", evt) + return + } + } + }() + for i := 0; i < N; i++ { + s1.Peerstore().AddAddrs(peers[i].LocalPeer(), []ma.Multiaddr{peers[i].ListenAddresses()[0]}, time.Hour) + _, err := s1.DialPeer(context.Background(), peers[i].LocalPeer()) + require.NoError(t, err) + } + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("expected all connectedness events to be completed") + } + + // Disconnect some peers + done = make(chan struct{}) + go func() { + defer close(done) + for i := 0; i < N/2; i++ { + e := <-sub1.Out() + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Error("invalid event received", e) + return + } + if evt.Connectedness != network.NotConnected { + t.Errorf("invalid event received: expected: NotConnected, got: %s", evt) + return + } + } + }() + for i := 0; i < N/2; i++ { + err := s1.ClosePeer(peers[i].LocalPeer()) + require.NoError(t, err) + } + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("expected all disconnected events to be completed") + } + + // Check for disconnected events on swarm close + done = make(chan struct{}) + go func() { + defer close(done) + for i := N / 2; i < N; i++ { + e := <-sub1.Out() + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Error("invalid event received", e) + return + } + if evt.Connectedness != network.NotConnected { + t.Errorf("invalid event received: expected: NotConnected, got: %s", evt) + return + } + } + }() + s1.Close() + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("expected all disconnected events after swarm close to be completed") + } +} + +func TestConnectednessEventDeadlock(t *testing.T) { + s1, sub1 := newSwarmWithSubscription(t) + const N = 100 + peers := make([]*Swarm, N) + for i := 0; i < N; i++ { + peers[i] = swarmt.GenSwarm(t) + } + + // First check all connected events + done := make(chan struct{}) + go func() { + defer close(done) + count := 0 + for count < N { + e := <-sub1.Out() + // sleep to simulate a slow consumer + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Error("invalid event received", e) + return + } + if evt.Connectedness != network.Connected { + continue + } + count++ + s1.ClosePeer(evt.Peer) + } + }() + for i := 0; i < N; i++ { + s1.Peerstore().AddAddrs(peers[i].LocalPeer(), []ma.Multiaddr{peers[i].ListenAddresses()[0]}, time.Hour) + go func(i int) { + _, err := s1.DialPeer(context.Background(), peers[i].LocalPeer()) + assert.NoError(t, err) + }(i) + } + select { + case <-done: + case <-time.After(100 * time.Second): + t.Fatal("expected all connectedness events to be completed") + } +} + +func TestConnectednessEventDeadlockWithDial(t *testing.T) { + s1, sub1 := newSwarmWithSubscription(t) + const N = 200 + peers := make([]*Swarm, N) + for i := 0; i < N; i++ { + peers[i] = swarmt.GenSwarm(t) + } + peers2 := make([]*Swarm, N) + for i := 0; i < N; i++ { + peers2[i] = swarmt.GenSwarm(t) + } + + // First check all connected events + done := make(chan struct{}) + var subWG sync.WaitGroup + subWG.Add(1) + go func() { + defer subWG.Done() + count := 0 + for { + var e interface{} + select { + case e = <-sub1.Out(): + case <-done: + return + } + // sleep to simulate a slow consumer + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Error("invalid event received", e) + return + } + if evt.Connectedness != network.Connected { + continue + } + if count < N { + time.Sleep(10 * time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) + s1.Peerstore().AddAddrs(peers2[count].LocalPeer(), []ma.Multiaddr{peers2[count].ListenAddresses()[0]}, time.Hour) + s1.DialPeer(ctx, peers2[count].LocalPeer()) + count++ + cancel() + } + } + }() + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + s1.Peerstore().AddAddrs(peers[i].LocalPeer(), []ma.Multiaddr{peers[i].ListenAddresses()[0]}, time.Hour) + go func(i int) { + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + s1.DialPeer(ctx, peers[i].LocalPeer()) + cancel() + wg.Done() + }(i) + } + wg.Wait() + s1.Close() + + close(done) + subWG.Wait() +} diff --git a/go-libp2p/p2p/net/swarm/swarm_metrics.go b/go-libp2p/p2p/net/swarm/swarm_metrics.go index 28564e9..b5c0f2e 100644 --- a/go-libp2p/p2p/net/swarm/swarm_metrics.go +++ b/go-libp2p/p2p/net/swarm/swarm_metrics.go @@ -128,7 +128,7 @@ type MetricsTracer interface { OpenedConnection(network.Direction, crypto.PubKey, network.ConnectionState, ma.Multiaddr) ClosedConnection(network.Direction, time.Duration, network.ConnectionState, ma.Multiaddr) CompletedHandshake(time.Duration, network.ConnectionState, ma.Multiaddr) - FailedDialing(ma.Multiaddr, error) + FailedDialing(ma.Multiaddr, error, error) DialCompleted(success bool, totalDials int) DialRankingDelay(d time.Duration) UpdatedBlackHoleFilterState(name string, state blackHoleState, nextProbeAfter int, successFraction float64) @@ -166,7 +166,7 @@ func appendConnectionState(tags []string, cs network.ConnectionState) []string { // This shouldn't happen, unless the transport doesn't properly set the Transport field in the ConnectionState. tags = append(tags, "unknown") } else { - tags = append(tags, string(cs.Transport)) + tags = append(tags, cs.Transport) } // These might be empty, depending on the transport. // For example, QUIC doesn't set security nor muxer. @@ -216,18 +216,28 @@ func (m *metricsTracer) CompletedHandshake(t time.Duration, cs network.Connectio connHandshakeLatency.WithLabelValues(*tags...).Observe(t.Seconds()) } -func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, err error) { +func (m *metricsTracer) FailedDialing(addr ma.Multiaddr, dialErr error, cause error) { transport := metricshelper.GetTransport(addr) e := "other" - if errors.Is(err, context.Canceled) { - e = "canceled" - } else if errors.Is(err, context.DeadlineExceeded) { + // dial deadline exceeded or the the parent contexts deadline exceeded + if errors.Is(dialErr, context.DeadlineExceeded) || errors.Is(cause, context.DeadlineExceeded) { e = "deadline" + } else if errors.Is(dialErr, context.Canceled) { + // dial was cancelled. + if errors.Is(cause, context.Canceled) { + // parent context was canceled + e = "application canceled" + } else if errors.Is(cause, errConcurrentDialSuccessful) { + e = "canceled: concurrent dial successful" + } else { + // something else + e = "canceled: other" + } } else { - nerr, ok := err.(net.Error) + nerr, ok := dialErr.(net.Error) if ok && nerr.Timeout() { e = "timeout" - } else if strings.Contains(err.Error(), "connect: connection refused") { + } else if strings.Contains(dialErr.Error(), "connect: connection refused") { e = "connection refused" } } diff --git a/go-libp2p/p2p/net/swarm/swarm_metrics_test.go b/go-libp2p/p2p/net/swarm/swarm_metrics_test.go index 25e13f3..e415c55 100644 --- a/go-libp2p/p2p/net/swarm/swarm_metrics_test.go +++ b/go-libp2p/p2p/net/swarm/swarm_metrics_test.go @@ -29,7 +29,7 @@ func BenchmarkMetricsConnOpen(b *testing.B) { } _, pub, err := crypto.GenerateEd25519Key(rand.Reader) require.NoError(b, err) - quicAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") + quicAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") tcpAddr := ma.StringCast("/ip4/1.2.3.4/tcp/1/") tr := NewMetricsTracer() for i := 0; i < b.N; i++ { @@ -53,7 +53,7 @@ func TestMetricsNoAllocNoCover(t *testing.T) { {StreamMultiplexer: "yamux", Security: "tls", Transport: "tcp", UsedEarlyMuxerNegotiation: true}, {StreamMultiplexer: "yamux", Security: "noise", Transport: "tcp", UsedEarlyMuxerNegotiation: false}, {StreamMultiplexer: "", Security: "", Transport: "quic"}, - {StreamMultiplexer: "mplex", Security: "noise", Transport: "tcp"}, + {StreamMultiplexer: "another-yamux", Security: "noise", Transport: "tcp"}, } directions := []network.Direction{network.DirInbound, network.DirOutbound} @@ -91,7 +91,7 @@ func TestMetricsNoAllocNoCover(t *testing.T) { "CompletedHandshake": func() { mt.CompletedHandshake(time.Duration(mrand.Intn(100))*time.Second, randItem(connections), randItem(addrs)) }, - "FailedDialing": func() { mt.FailedDialing(randItem(addrs), randItem(errors)) }, + "FailedDialing": func() { mt.FailedDialing(randItem(addrs), randItem(errors), randItem(errors)) }, "DialCompleted": func() { mt.DialCompleted(mrand.Intn(2) == 1, mrand.Intn(10)) }, "DialRankingDelay": func() { mt.DialRankingDelay(time.Duration(mrand.Intn(1e10))) }, "UpdatedBlackHoleFilterState": func() { diff --git a/go-libp2p/p2p/net/swarm/swarm_stream.go b/go-libp2p/p2p/net/swarm/swarm_stream.go index d372bcd..b7846ad 100644 --- a/go-libp2p/p2p/net/swarm/swarm_stream.go +++ b/go-libp2p/p2p/net/swarm/swarm_stream.go @@ -22,7 +22,10 @@ type Stream struct { conn *Conn scope network.StreamManagementScope - closeOnce sync.Once + closeMx sync.Mutex + isClosed bool + // acceptStreamGoroutineCompleted indicates whether the goroutine handling the incoming stream has exited + acceptStreamGoroutineCompleted bool protocol atomic.Pointer[protocol.ID] @@ -76,7 +79,7 @@ func (s *Stream) Write(p []byte) (int, error) { // resources. func (s *Stream) Close() error { err := s.stream.Close() - s.closeOnce.Do(s.remove) + s.closeAndRemoveStream() return err } @@ -84,10 +87,25 @@ func (s *Stream) Close() error { // associated resources. func (s *Stream) Reset() error { err := s.stream.Reset() - s.closeOnce.Do(s.remove) + s.closeAndRemoveStream() return err } +func (s *Stream) closeAndRemoveStream() { + s.closeMx.Lock() + defer s.closeMx.Unlock() + if s.isClosed { + return + } + s.isClosed = true + // We don't want to keep swarm from closing till the stream handler has exited + s.conn.swarm.refs.Done() + // Cleanup the stream from connection only after the stream handler has completed + if s.acceptStreamGoroutineCompleted { + s.conn.removeStream(s) + } +} + // CloseWrite closes the stream for writing, flushing all data and sending an EOF. // This function does not free resources, call Close or Reset when done with the // stream. @@ -101,9 +119,16 @@ func (s *Stream) CloseRead() error { return s.stream.CloseRead() } -func (s *Stream) remove() { - s.conn.removeStream(s) - s.conn.swarm.refs.Done() +func (s *Stream) completeAcceptStreamGoroutine() { + s.closeMx.Lock() + defer s.closeMx.Unlock() + if s.acceptStreamGoroutineCompleted { + return + } + s.acceptStreamGoroutineCompleted = true + if s.isClosed { + s.conn.removeStream(s) + } } // Protocol returns the protocol negotiated on this stream (if set). diff --git a/go-libp2p/p2p/net/swarm/swarm_test.go b/go-libp2p/p2p/net/swarm/swarm_test.go index 2385545..3d92690 100644 --- a/go-libp2p/p2p/net/swarm/swarm_test.go +++ b/go-libp2p/p2p/net/swarm/swarm_test.go @@ -21,11 +21,11 @@ import ( "github.com/libp2p/go-libp2p/p2p/net/swarm" . "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" - "github.com/golang/mock/gomock" logging "github.com/ipfs/go-log/v2" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) var log = logging.Logger("swarm_test") @@ -390,7 +390,7 @@ func TestTypedNilConn(t *testing.T) { func TestPreventDialListenAddr(t *testing.T) { s := GenSwarm(t, OptDialOnly) - if err := s.Listen(ma.StringCast("/ip4/0.0.0.0/udp/0/quic")); err != nil { + if err := s.Listen(ma.StringCast("/ip4/0.0.0.0/udp/0/quic-v1")); err != nil { t.Fatal(err) } addrs, err := s.InterfaceListenAddresses() @@ -445,16 +445,16 @@ func TestStreamCount(t *testing.T) { <-streamAccepted } require.Eventually(t, func() bool { return len(streams) == 10 }, 5*time.Second, 10*time.Millisecond) - require.Equal(t, countStreams(), 10) + require.Equal(t, 10, countStreams()) (<-streams).Reset() (<-streams).Close() - require.Equal(t, countStreams(), 8) + require.Equal(t, 8, countStreams()) str, err := s1.NewStream(context.Background(), s2.LocalPeer()) require.NoError(t, err) - require.Equal(t, countStreams(), 9) + require.Equal(t, 9, countStreams()) str.Close() - require.Equal(t, countStreams(), 8) + require.Equal(t, 8, countStreams()) } func TestResourceManager(t *testing.T) { @@ -552,7 +552,7 @@ func TestListenCloseCount(t *testing.T) { t.Fatal(err) } listenedAddrs := s.ListenAddresses() - require.Equal(t, 2, len(listenedAddrs)) + require.Len(t, listenedAddrs, 2) var addrToClose ma.Multiaddr for _, addr := range listenedAddrs { if _, err := addr.ValueForProtocol(ma.P_QUIC_V1); err == nil { @@ -564,7 +564,7 @@ func TestListenCloseCount(t *testing.T) { s.ListenClose(addrToClose) remainingAddrs := s.ListenAddresses() - require.Equal(t, 1, len(remainingAddrs)) + require.Len(t, remainingAddrs, 1) _, err := remainingAddrs[0].ValueForProtocol(ma.P_TCP) require.NoError(t, err, "expected the TCP address to still be present") } diff --git a/go-libp2p/p2p/net/swarm/testing/testing.go b/go-libp2p/p2p/net/swarm/testing/testing.go index b052a99..627114f 100644 --- a/go-libp2p/p2p/net/swarm/testing/testing.go +++ b/go-libp2p/p2p/net/swarm/testing/testing.go @@ -21,11 +21,12 @@ import ( "github.com/libp2p/go-libp2p/p2p/muxer/yamux" "github.com/libp2p/go-libp2p/p2p/net/swarm" tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" - quic "github.com/libp2p/go-libp2p/p2p/transport/quic" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" "github.com/libp2p/go-libp2p/p2p/transport/tcp" ma "github.com/multiformats/go-multiaddr" + "github.com/quic-go/quic-go" "github.com/stretchr/testify/require" ) @@ -175,11 +176,11 @@ func GenSwarm(t *testing.T, opts ...Option) *swarm.Swarm { } } if !cfg.disableQUIC { - reuse, err := quicreuse.NewConnManager([32]byte{}) + reuse, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) if err != nil { t.Fatal(err) } - quicTransport, err := quic.NewTransport(priv, reuse, nil, cfg.connectionGater, nil) + quicTransport, err := libp2pquic.NewTransport(priv, reuse, nil, cfg.connectionGater, nil) if err != nil { t.Fatal(err) } @@ -187,7 +188,7 @@ func GenSwarm(t *testing.T, opts ...Option) *swarm.Swarm { t.Fatal(err) } if !cfg.dialOnly { - if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")); err != nil { + if err := s.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")); err != nil { t.Fatal(err) } } diff --git a/go-libp2p/p2p/net/swarm/util_test.go b/go-libp2p/p2p/net/swarm/util_test.go index 66246b5..ab9baa7 100644 --- a/go-libp2p/p2p/net/swarm/util_test.go +++ b/go-libp2p/p2p/net/swarm/util_test.go @@ -20,7 +20,7 @@ func TestIsFdConsuming(t *testing.T) { isFdConsuming: true, }, "quic": { - addr: "/ip4/127.0.0.1/udp/0/quic", + addr: "/ip4/127.0.0.1/udp/0/quic-v1", isFdConsuming: false, }, "addr-without-registered-transport": { diff --git a/go-libp2p/p2p/net/upgrader/listener.go b/go-libp2p/p2p/net/upgrader/listener.go index 0871d2f..8af2791 100644 --- a/go-libp2p/p2p/net/upgrader/listener.go +++ b/go-libp2p/p2p/net/upgrader/listener.go @@ -37,7 +37,7 @@ type listener struct { // Close closes the listener. func (l *listener) Close() error { - // Do this first to try to get any relevent errors. + // Do this first to try to get any relevant errors. err := l.Listener.Close() l.cancel() diff --git a/go-libp2p/p2p/net/upgrader/listener_test.go b/go-libp2p/p2p/net/upgrader/listener_test.go index 331e973..14800e5 100644 --- a/go-libp2p/p2p/net/upgrader/listener_test.go +++ b/go-libp2p/p2p/net/upgrader/listener_test.go @@ -18,10 +18,10 @@ import ( "github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/p2p/net/upgrader" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) func createListener(t *testing.T, u transport.Upgrader) transport.Listener { @@ -112,7 +112,7 @@ func TestConnectionsClosedIfNotAccepted(t *testing.T) { } time.Sleep(timeout) - require.Nil(<-errCh) + require.NoError(<-errCh) } func TestFailedUpgradeOnListen(t *testing.T) { diff --git a/go-libp2p/p2p/net/upgrader/upgrader.go b/go-libp2p/p2p/net/upgrader/upgrader.go index d18c16e..3a6f8b9 100644 --- a/go-libp2p/p2p/net/upgrader/upgrader.go +++ b/go-libp2p/p2p/net/upgrader/upgrader.go @@ -152,7 +152,8 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma return nil, ipnet.ErrNotInPrivateNetwork } - sconn, security, server, err := u.setupSecurity(ctx, conn, p, dir) + isServer := dir == network.DirInbound + sconn, security, err := u.setupSecurity(ctx, conn, p, isServer) if err != nil { conn.Close() return nil, fmt.Errorf("failed to negotiate security protocol: %w", err) @@ -179,7 +180,7 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma } } - muxer, smconn, err := u.setupMuxer(ctx, sconn, server, connScope.PeerScope()) + muxer, smconn, err := u.setupMuxer(ctx, sconn, isServer, connScope.PeerScope()) if err != nil { sconn.Close() return nil, fmt.Errorf("failed to negotiate stream multiplexer: %w", err) @@ -199,20 +200,17 @@ func (u *upgrader) upgrade(ctx context.Context, t transport.Transport, maconn ma return tc, nil } -func (u *upgrader) setupSecurity(ctx context.Context, conn net.Conn, p peer.ID, dir network.Direction) (sec.SecureConn, protocol.ID, bool, error) { - isServer := dir == network.DirInbound - var st sec.SecureTransport - var err error - st, isServer, err = u.negotiateSecurity(ctx, conn, isServer) +func (u *upgrader) setupSecurity(ctx context.Context, conn net.Conn, p peer.ID, isServer bool) (sec.SecureConn, protocol.ID, error) { + st, err := u.negotiateSecurity(ctx, conn, isServer) if err != nil { - return nil, "", false, err + return nil, "", err } if isServer { sconn, err := st.SecureInbound(ctx, conn, p) - return sconn, st.ID(), true, err + return sconn, st.ID(), err } sconn, err := st.SecureOutbound(ctx, conn, p) - return sconn, st.ID(), false, err + return sconn, st.ID(), err } func (u *upgrader) negotiateMuxer(nc net.Conn, isServer bool) (*StreamMuxer, error) { @@ -308,41 +306,38 @@ func (u *upgrader) getSecurityByID(id protocol.ID) sec.SecureTransport { return nil } -func (u *upgrader) negotiateSecurity(ctx context.Context, insecure net.Conn, server bool) (sec.SecureTransport, bool, error) { +func (u *upgrader) negotiateSecurity(ctx context.Context, insecure net.Conn, server bool) (sec.SecureTransport, error) { type result struct { - proto protocol.ID - iamserver bool - err error + proto protocol.ID + err error } done := make(chan result, 1) go func() { if server { var r result - r.iamserver = true r.proto, _, r.err = u.securityMuxer.Negotiate(insecure) done <- r return } var r result - r.proto, r.iamserver, r.err = mss.SelectWithSimopenOrFail(u.securityIDs, insecure) + r.proto, r.err = mss.SelectOneOf(u.securityIDs, insecure) done <- r }() select { case r := <-done: if r.err != nil { - return nil, false, r.err + return nil, r.err } if s := u.getSecurityByID(r.proto); s != nil { - return s, r.iamserver, nil + return s, nil } - return nil, false, fmt.Errorf("selected unknown security transport: %s", r.proto) + return nil, fmt.Errorf("selected unknown security transport: %s", r.proto) case <-ctx.Done(): - // We *must* do this. We have outstanding work on the connection - // and it's no longer safe to use. + // We *must* do this. We have outstanding work on the connection, and it's no longer safe to use. insecure.Close() <-done // wait to stop using the connection. - return nil, false, ctx.Err() + return nil, ctx.Err() } } diff --git a/go-libp2p/p2p/net/upgrader/upgrader_test.go b/go-libp2p/p2p/net/upgrader/upgrader_test.go index b61ba8a..920ccaa 100644 --- a/go-libp2p/p2p/net/upgrader/upgrader_test.go +++ b/go-libp2p/p2p/net/upgrader/upgrader_test.go @@ -18,10 +18,10 @@ import ( "github.com/libp2p/go-libp2p/p2p/muxer/yamux" "github.com/libp2p/go-libp2p/p2p/net/upgrader" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) func createUpgrader(t *testing.T) (peer.ID, transport.Upgrader) { diff --git a/go-libp2p/p2p/protocol/circuitv2/client/dial.go b/go-libp2p/p2p/protocol/circuitv2/client/dial.go index ecf5d3a..2716525 100644 --- a/go-libp2p/p2p/protocol/circuitv2/client/dial.go +++ b/go-libp2p/p2p/protocol/circuitv2/client/dial.go @@ -179,7 +179,7 @@ func (c *Client) connect(s network.Stream, dest peer.AddrInfo) (*Conn, error) { // relay connection and we mark the connection as transient. var stat network.ConnStats if limit := msg.GetLimit(); limit != nil { - stat.Transient = true + stat.Limited = true stat.Extra = make(map[interface{}]interface{}) stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second stat.Extra[StatLimitData] = limit.GetData() diff --git a/go-libp2p/p2p/protocol/circuitv2/client/handlers.go b/go-libp2p/p2p/protocol/circuitv2/client/handlers.go index 6b5361b..389f0e4 100644 --- a/go-libp2p/p2p/protocol/circuitv2/client/handlers.go +++ b/go-libp2p/p2p/protocol/circuitv2/client/handlers.go @@ -22,6 +22,8 @@ func (c *Client) handleStreamV2(s network.Stream) { defer rd.Close() writeResponse := func(status pbv2.Status) error { + s.SetWriteDeadline(time.Now().Add(StreamTimeout)) + defer s.SetWriteDeadline(time.Time{}) wr := util.NewDelimitedWriter(s) var msg pbv2.StopMessage @@ -67,7 +69,7 @@ func (c *Client) handleStreamV2(s network.Stream) { // relay connection and we mark the connection as transient. var stat network.ConnStats if limit := msg.GetLimit(); limit != nil { - stat.Transient = true + stat.Limited = true stat.Extra = make(map[interface{}]interface{}) stat.Extra[StatLimitDuration] = time.Duration(limit.GetDuration()) * time.Second stat.Extra[StatLimitData] = limit.GetData() diff --git a/go-libp2p/p2p/protocol/circuitv2/client/transport.go b/go-libp2p/p2p/protocol/circuitv2/client/transport.go index e08d557..2c9e49f 100644 --- a/go-libp2p/p2p/protocol/circuitv2/client/transport.go +++ b/go-libp2p/p2p/protocol/circuitv2/client/transport.go @@ -50,6 +50,7 @@ var _ io.Closer = (*Client)(nil) func (c *Client) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { connScope, err := c.host.Network().ResourceManager().OpenConnection(network.DirOutbound, false, a) + if err != nil { return nil, err } diff --git a/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go b/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go index 2435308..28698d9 100644 --- a/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go +++ b/go-libp2p/p2p/protocol/circuitv2/relay/constraints.go @@ -29,7 +29,7 @@ type constraints struct { total []time.Time peers map[peer.ID][]time.Time ips map[string][]time.Time - asns map[string][]time.Time + asns map[uint32][]time.Time } // newConstraints creates a new constraints object. @@ -40,7 +40,7 @@ func newConstraints(rc *Resources) *constraints { rc: rc, peers: make(map[peer.ID][]time.Time), ips: make(map[string][]time.Time), - asns: make(map[string][]time.Time), + asns: make(map[uint32][]time.Time), } } @@ -73,10 +73,10 @@ func (c *constraints) AddReservation(p peer.ID, a ma.Multiaddr) error { } var asnReservations []time.Time - var asn string + var asn uint32 if ip.To4() == nil { - asn, _ = asnutil.Store.AsnForIPv6(ip) - if asn != "" { + asn = asnutil.AsnForIPv6(ip) + if asn != 0 { asnReservations = c.asns[asn] if len(asnReservations) >= c.rc.MaxReservationsPerASN { return errTooManyReservationsForASN @@ -93,7 +93,7 @@ func (c *constraints) AddReservation(p peer.ID, a ma.Multiaddr) error { ipReservations = append(ipReservations, expiry) c.ips[ip.String()] = ipReservations - if asn != "" { + if asn != 0 { asnReservations = append(asnReservations, expiry) c.asns[asn] = asnReservations } diff --git a/go-libp2p/p2p/protocol/circuitv2/relay/relay.go b/go-libp2p/p2p/protocol/circuitv2/relay/relay.go index e3c8f47..1629a6d 100644 --- a/go-libp2p/p2p/protocol/circuitv2/relay/relay.go +++ b/go-libp2p/p2p/protocol/circuitv2/relay/relay.go @@ -19,7 +19,6 @@ import ( logging "github.com/ipfs/go-log/v2" pool "github.com/libp2p/go-buffer-pool" - asnutil "github.com/libp2p/go-libp2p-asn-util" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" ) @@ -296,7 +295,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) pbv2.Statu destConns := r.conns[dest.ID] if destConns >= r.rc.MaxCircuits { r.mx.Unlock() - log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID) + log.Debugf("refusing connection from %s to %s; too many connections to %s", src, dest.ID, dest.ID) fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED) return pbv2.Status_RESOURCE_LIMIT_EXCEEDED } @@ -557,6 +556,8 @@ func (r *Relay) handleError(s network.Stream, status pbv2.Status) { } func (r *Relay) writeResponse(s network.Stream, status pbv2.Status, rsvp *pbv2.Reservation, limit *pbv2.Limit) error { + s.SetWriteDeadline(time.Now().Add(StreamTimeout)) + defer s.SetWriteDeadline(time.Time{}) wr := util.NewDelimitedWriter(s) var msg pbv2.HopMessage @@ -624,8 +625,6 @@ func (r *Relay) makeLimitMsg(p peer.ID) *pbv2.Limit { } func (r *Relay) background() { - asnutil.Store.Init() - ticker := time.NewTicker(time.Minute) defer ticker.Stop() diff --git a/go-libp2p/p2p/protocol/circuitv2/relay/relay_test.go b/go-libp2p/p2p/protocol/circuitv2/relay/relay_test.go index a229fe4..e5d32b0 100644 --- a/go-libp2p/p2p/protocol/circuitv2/relay/relay_test.go +++ b/go-libp2p/p2p/protocol/circuitv2/relay/relay_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/metrics" "github.com/libp2p/go-libp2p/core/network" @@ -23,6 +24,7 @@ import ( "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" "github.com/libp2p/go-libp2p/p2p/transport/tcp" + "github.com/stretchr/testify/require" ma "github.com/multiformats/go-multiaddr" ) @@ -49,7 +51,8 @@ func getNetHosts(t *testing.T, ctx context.Context, n int) (hosts []host.Host, u } bwr := metrics.NewBandwidthCounter() - netw, err := swarm.NewSwarm(p, ps, eventbus.NewBus(), swarm.WithMetrics(bwr)) + bus := eventbus.NewBus() + netw, err := swarm.NewSwarm(p, ps, bus, swarm.WithMetrics(bwr)) if err != nil { t.Fatal(err) } @@ -70,7 +73,7 @@ func getNetHosts(t *testing.T, ctx context.Context, n int) (hosts []host.Host, u t.Fatal(err) } - h := bhost.NewBlankHost(netw) + h := bhost.NewBlankHost(netw, bhost.WithEventBus(bus)) hosts = append(hosts, h) } @@ -145,20 +148,41 @@ func TestBasicRelay(t *testing.T) { t.Fatal(err) } + sub, err := hosts[2].EventBus().Subscribe(new(event.EvtPeerConnectednessChanged)) + require.NoError(t, err) + err = hosts[2].Connect(ctx, peer.AddrInfo{ID: hosts[0].ID(), Addrs: []ma.Multiaddr{raddr}}) if err != nil { t.Fatal(err) } + for { + var e interface{} + select { + case e = <-sub.Out(): + case <-time.After(2 * time.Second): + t.Fatal("expected limited connectivity event") + } + evt, ok := e.(event.EvtPeerConnectednessChanged) + if !ok { + t.Fatalf("invalid event: %s", e) + } + if evt.Peer == hosts[0].ID() { + if evt.Connectedness != network.Limited { + t.Fatalf("expected limited connectivity %s", evt.Connectedness) + } + break + } + } conns := hosts[2].Network().ConnsToPeer(hosts[0].ID()) if len(conns) != 1 { t.Fatalf("expected 1 connection, but got %d", len(conns)) } - if !conns[0].Stat().Transient { + if !conns[0].Stat().Limited { t.Fatal("expected transient connection") } - s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + s, err := hosts[2].NewStream(network.WithAllowLimitedConn(ctx, "test"), hosts[0].ID(), "test") if err != nil { t.Fatal(err) } @@ -229,11 +253,11 @@ func TestRelayLimitTime(t *testing.T) { if len(conns) != 1 { t.Fatalf("expected 1 connection, but got %d", len(conns)) } - if !conns[0].Stat().Transient { + if !conns[0].Stat().Limited { t.Fatal("expected transient connection") } - s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + s, err := hosts[2].NewStream(network.WithAllowLimitedConn(ctx, "test"), hosts[0].ID(), "test") if err != nil { t.Fatal(err) } @@ -315,11 +339,11 @@ func TestRelayLimitData(t *testing.T) { if len(conns) != 1 { t.Fatalf("expected 1 connection, but got %d", len(conns)) } - if !conns[0].Stat().Transient { + if !conns[0].Stat().Limited { t.Fatal("expected transient connection") } - s, err := hosts[2].NewStream(network.WithUseTransient(ctx, "test"), hosts[0].ID(), "test") + s, err := hosts[2].NewStream(network.WithAllowLimitedConn(ctx, "test"), hosts[0].ID(), "test") if err != nil { t.Fatal(err) } diff --git a/go-libp2p/p2p/protocol/holepunch/holepunch_test.go b/go-libp2p/p2p/protocol/holepunch/holepunch_test.go index 29d589c..23593c7 100644 --- a/go-libp2p/p2p/protocol/holepunch/holepunch_test.go +++ b/go-libp2p/p2p/protocol/holepunch/holepunch_test.go @@ -96,8 +96,8 @@ func TestNoHolePunchIfDirectConnExists(t *testing.T) { require.GreaterOrEqual(t, nc2, 1) require.NoError(t, hps.DirectConnect(h2.ID())) - require.Equal(t, len(h1.Network().ConnsToPeer(h2.ID())), nc1) - require.Equal(t, len(h2.Network().ConnsToPeer(h1.ID())), nc2) + require.Len(t, h1.Network().ConnsToPeer(h2.ID()), nc1) + require.Len(t, h2.Network().ConnsToPeer(h1.ID()), nc2) require.Empty(t, tr.getEvents()) } @@ -120,13 +120,13 @@ func TestDirectDialWorks(t *testing.T) { h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.ConnectedAddrTTL) // try to hole punch without any connection and streams, if it works -> it's a direct connection - require.Len(t, h1.Network().ConnsToPeer(h2.ID()), 0) + require.Empty(t, h1.Network().ConnsToPeer(h2.ID())) require.NoError(t, h1ps.DirectConnect(h2.ID())) require.GreaterOrEqual(t, len(h1.Network().ConnsToPeer(h2.ID())), 1) require.GreaterOrEqual(t, len(h2.Network().ConnsToPeer(h1.ID())), 1) events := tr.getEvents() require.Len(t, events, 1) - require.Equal(t, events[0].Type, holepunch.DirectDialEvtT) + require.Equal(t, holepunch.DirectDialEvtT, events[0].Type) } func TestEndToEndSimConnect(t *testing.T) { @@ -247,7 +247,6 @@ func TestFailuresOnInitiator(t *testing.T) { require.Contains(t, err.Error(), tc.errMsg) } }) - } } @@ -340,7 +339,7 @@ func TestFailuresOnResponder(t *testing.T) { defer h2.Close() defer relay.Close() - s, err := h2.NewStream(network.WithUseTransient(context.Background(), "holepunch"), h1.ID(), holepunch.Protocol) + s, err := h2.NewStream(network.WithAllowLimitedConn(context.Background(), "holepunch"), h1.ID(), holepunch.Protocol) require.NoError(t, err) go tc.initiator(s) @@ -361,7 +360,6 @@ func TestFailuresOnResponder(t *testing.T) { require.Len(t, errs, 1) require.Contains(t, errs[0], tc.errMsg) }) - } } diff --git a/go-libp2p/p2p/protocol/holepunch/holepuncher.go b/go-libp2p/p2p/protocol/holepunch/holepuncher.go index b651bd7..479376e 100644 --- a/go-libp2p/p2p/protocol/holepunch/holepuncher.go +++ b/go-libp2p/p2p/protocol/holepunch/holepuncher.go @@ -174,7 +174,7 @@ func (hp *holePuncher) directConnect(rp peer.ID) error { // initiateHolePunch opens a new hole punching coordination stream, // exchanges the addresses and measures the RTT. func (hp *holePuncher) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, []ma.Multiaddr, time.Duration, error) { - hpCtx := network.WithUseTransient(hp.ctx, "hole-punch") + hpCtx := network.WithAllowLimitedConn(hp.ctx, "hole-punch") sCtx := network.WithNoDial(hpCtx, "hole-punch") str, err := hp.host.NewStream(sCtx, rp, Protocol) diff --git a/go-libp2p/p2p/protocol/holepunch/metrics_noalloc_test.go b/go-libp2p/p2p/protocol/holepunch/metrics_noalloc_test.go index 968354f..eb04eed 100644 --- a/go-libp2p/p2p/protocol/holepunch/metrics_noalloc_test.go +++ b/go-libp2p/p2p/protocol/holepunch/metrics_noalloc_test.go @@ -14,14 +14,14 @@ func TestNoCoverNoAllocMetrics(t *testing.T) { addrs1 := [][]ma.Multiaddr{ { ma.StringCast("/ip4/0.0.0.0/tcp/1"), - ma.StringCast("/ip4/1.2.3.4/udp/2/quic"), + ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1"), }, nil, } addrs2 := [][]ma.Multiaddr{ { ma.StringCast("/ip4/1.2.3.4/tcp/3"), - ma.StringCast("/ip4/1.2.3.4/udp/4/quic"), + ma.StringCast("/ip4/1.2.3.4/udp/4/quic-v1"), }, nil, } diff --git a/go-libp2p/p2p/protocol/holepunch/metrics_test.go b/go-libp2p/p2p/protocol/holepunch/metrics_test.go index 6d7bf16..86cb59d 100644 --- a/go-libp2p/p2p/protocol/holepunch/metrics_test.go +++ b/go-libp2p/p2p/protocol/holepunch/metrics_test.go @@ -24,10 +24,8 @@ func TestHolePunchOutcomeCounter(t *testing.T) { t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1") t2 := ma.StringCast("/ip4/1.2.3.4/tcp/2") - q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic") - q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic") - q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1") type testcase struct { name string @@ -39,35 +37,34 @@ func TestHolePunchOutcomeCounter(t *testing.T) { testcases := []testcase{ { name: "connection success", - theirAddrs: []ma.Multiaddr{t1, q1}, - ourAddrs: []ma.Multiaddr{t2, q2}, + theirAddrs: []ma.Multiaddr{t1, q1v1}, + ourAddrs: []ma.Multiaddr{t2, q2v1}, conn: &mockConnMultiaddrs{local: t1, remote: t2}, result: map[[3]string]int{ - [...]string{"ip4", "tcp", "success"}: 1, - [...]string{"ip4", "quic", "cancelled"}: 1, + [...]string{"ip4", "tcp", "success"}: 1, + [...]string{"ip4", "quic-v1", "cancelled"}: 1, }, }, { name: "connection failed", theirAddrs: []ma.Multiaddr{t1}, - ourAddrs: []ma.Multiaddr{t2, q2}, + ourAddrs: []ma.Multiaddr{t2, q2v1}, conn: nil, result: map[[3]string]int{ - [...]string{"ip4", "tcp", "failed"}: 1, - [...]string{"ip4", "quic", "no_suitable_address"}: 1, + [...]string{"ip4", "tcp", "failed"}: 1, + [...]string{"ip4", "quic-v1", "no_suitable_address"}: 1, }, }, { name: "no_suitable_address", - theirAddrs: []ma.Multiaddr{t1, q1}, - ourAddrs: []ma.Multiaddr{t2, q2, q1v1}, - conn: &mockConnMultiaddrs{local: q1, remote: q2}, + theirAddrs: []ma.Multiaddr{t1, q1v1}, + ourAddrs: []ma.Multiaddr{t2, q2v1}, + conn: &mockConnMultiaddrs{local: q1v1, remote: q2v1}, result: map[[3]string]int{ - [...]string{"ip4", "tcp", "cancelled"}: 1, - [...]string{"ip4", "quic", "failed"}: 0, - [...]string{"ip4", "quic", "success"}: 1, - [...]string{"ip4", "tcp", "success"}: 0, - [...]string{"ip4", "quic-v1", "no_suitable_address"}: 1, + [...]string{"ip4", "tcp", "cancelled"}: 1, + [...]string{"ip4", "quic-v1", "failed"}: 0, + [...]string{"ip4", "quic-v1", "success"}: 1, + [...]string{"ip4", "tcp", "success"}: 0, }, }, } diff --git a/go-libp2p/p2p/protocol/holepunch/svc.go b/go-libp2p/p2p/protocol/holepunch/svc.go index 47bf434..9de0a11 100644 --- a/go-libp2p/p2p/protocol/holepunch/svc.go +++ b/go-libp2p/p2p/protocol/holepunch/svc.go @@ -182,7 +182,7 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, remo } if err := str.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil { - log.Debugf("error reserving memory for stream: %s, err") + log.Debugf("error reserving memory for stream: %s", err) return 0, nil, nil, err } defer str.Scope().ReleaseMemory(maxMsgSize) @@ -196,7 +196,7 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, remo str.SetDeadline(time.Now().Add(StreamTimeout)) if err := rd.ReadMsg(msg); err != nil { - return 0, nil, nil, fmt.Errorf("failed to read message from initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to read message from initiator: %w", err) } if t := msg.GetType(); t != pb.HolePunch_CONNECT { return 0, nil, nil, fmt.Errorf("expected CONNECT message from initiator but got %d", t) @@ -218,13 +218,13 @@ func (s *Service) incomingHolePunch(str network.Stream) (rtt time.Duration, remo msg.ObsAddrs = addrsToBytes(ownAddrs) tstart := time.Now() if err := wr.WriteMsg(msg); err != nil { - return 0, nil, nil, fmt.Errorf("failed to write CONNECT message to initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to write CONNECT message to initiator: %w", err) } // Read SYNC message msg.Reset() if err := rd.ReadMsg(msg); err != nil { - return 0, nil, nil, fmt.Errorf("failed to read message from initator: %w", err) + return 0, nil, nil, fmt.Errorf("failed to read message from initiator: %w", err) } if t := msg.GetType(); t != pb.HolePunch_SYNC { return 0, nil, nil, fmt.Errorf("expected SYNC message from initiator but got %d", t) diff --git a/go-libp2p/p2p/protocol/identify/id.go b/go-libp2p/p2p/protocol/identify/id.go index 6c07dbd..a91cc4f 100644 --- a/go-libp2p/p2p/protocol/identify/id.go +++ b/go-libp2p/p2p/protocol/identify/id.go @@ -34,24 +34,27 @@ import ( var log = logging.Logger("net/identify") +var Timeout = 30 * time.Second // timeout on all incoming Identify interactions + const ( // ID is the protocol.ID of version 1.0.0 of the identify service. ID = "/ipfs/id/1.0.0" // IDPush is the protocol.ID of the Identify push protocol. // It sends full identify messages containing the current state of the peer. IDPush = "/ipfs/id/push/1.0.0" -) -const ServiceName = "libp2p.identify" + ServiceName = "libp2p.identify" -const maxPushConcurrency = 32 - -var Timeout = 60 * time.Second // timeout on all incoming Identify interactions - -const ( - legacyIDSize = 2 * 1024 // 2k Bytes - signedIDSize = 8 * 1024 // 8K - maxMessages = 10 + legacyIDSize = 2 * 1024 + signedIDSize = 8 * 1024 + maxOwnIdentifyMsgSize = 4 * 1024 // smaller than what we accept. This is 4k to be compatible with rust-libp2p + maxMessages = 10 + maxPushConcurrency = 32 + // number of addresses to keep for peers we have disconnected from for peerstore.RecentlyConnectedTTL time + // This number can be small as we already filter peer addresses based on whether the peer is connected to us over + // localhost, private IP or public IP address + recentlyConnectedPeerMaxAddrs = 20 + connectedPeerMaxAddrs = 500 ) var defaultUserAgent = "github.com/libp2p/go-libp2p" @@ -159,7 +162,8 @@ type idService struct { addrMu sync.Mutex // our own observed addresses. - observedAddrs *ObservedAddrManager + observedAddrMgr *ObservedAddrManager + disableObservedAddrManager bool emitters struct { evtPeerProtocolsUpdated event.Emitter @@ -171,6 +175,12 @@ type idService struct { sync.Mutex snapshot identifySnapshot } + + natEmitter *natEmitter +} + +type normalizer interface { + NormalizeMultiaddr(ma.Multiaddr) ma.Multiaddr } // NewIDService constructs a new *idService and activates it by @@ -199,11 +209,27 @@ func NewIDService(h host.Host, opts ...Option) (*idService, error) { metricsTracer: cfg.metricsTracer, } - observedAddrs, err := NewObservedAddrManager(h) - if err != nil { - return nil, fmt.Errorf("failed to create observed address manager: %s", err) + var normalize func(ma.Multiaddr) ma.Multiaddr + if hn, ok := h.(normalizer); ok { + normalize = hn.NormalizeMultiaddr + } + + var err error + if cfg.disableObservedAddrManager { + s.disableObservedAddrManager = true + } else { + observedAddrs, err := NewObservedAddrManager(h.Network().ListenAddresses, + h.Addrs, h.Network().InterfaceListenAddresses, normalize) + if err != nil { + return nil, fmt.Errorf("failed to create observed address manager: %s", err) + } + natEmitter, err := newNATEmitter(h, observedAddrs, time.Minute) + if err != nil { + return nil, fmt.Errorf("failed to create nat emitter: %s", err) + } + s.natEmitter = natEmitter + s.observedAddrMgr = observedAddrs } - s.observedAddrs = observedAddrs s.emitters.evtPeerProtocolsUpdated, err = h.EventBus().Emitter(&event.EvtPeerProtocolsUpdated{}) if err != nil { @@ -341,17 +367,26 @@ func (ids *idService) sendPushes(ctx context.Context) { // Close shuts down the idService func (ids *idService) Close() error { ids.ctxCancel() - ids.observedAddrs.Close() + if !ids.disableObservedAddrManager { + ids.observedAddrMgr.Close() + ids.natEmitter.Close() + } ids.refCount.Wait() return nil } func (ids *idService) OwnObservedAddrs() []ma.Multiaddr { - return ids.observedAddrs.Addrs() + if ids.disableObservedAddrManager { + return nil + } + return ids.observedAddrMgr.Addrs() } func (ids *idService) ObservedAddrsFor(local ma.Multiaddr) []ma.Multiaddr { - return ids.observedAddrs.AddrsFor(local) + if ids.disableObservedAddrManager { + return nil + } + return ids.observedAddrMgr.AddrsFor(local) } // IdentifyConn runs the Identify protocol on a connection. @@ -400,8 +435,6 @@ func (ids *idService) IdentifyWait(c network.Conn) <-chan struct{} { ids.emitters.evtPeerIdentificationFailed.Emit(event.EvtPeerIdentificationFailed{Peer: c.RemotePeer(), Reason: err}) return } - - ids.emitters.evtPeerIdentificationCompleted.Emit(event.EvtPeerIdentificationCompleted{Peer: c.RemotePeer()}) }() return e.IdentifyWaitChan @@ -410,7 +443,7 @@ func (ids *idService) IdentifyWait(c network.Conn) <-chan struct{} { func (ids *idService) identifyConn(c network.Conn) error { ctx, cancel := context.WithTimeout(context.Background(), Timeout) defer cancel() - s, err := c.NewStream(network.WithUseTransient(ctx, "identify")) + s, err := c.NewStream(network.WithAllowLimitedConn(ctx, "identify")) if err != nil { log.Debugw("error opening identify stream", "peer", c.RemotePeer(), "error", err) return err @@ -555,10 +588,18 @@ func readAllIDMessages(r pbio.Reader, finalMsg proto.Message) error { } func (ids *idService) updateSnapshot() (updated bool) { - addrs := ids.Host.Addrs() - slices.SortFunc(addrs, func(a, b ma.Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) }) protos := ids.Host.Mux().Protocols() slices.Sort(protos) + + addrs := ids.Host.Addrs() + slices.SortFunc(addrs, func(a, b ma.Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) }) + + usedSpace := len(ids.ProtocolVersion) + len(ids.UserAgent) + for i := 0; i < len(protos); i++ { + usedSpace += len(protos[i]) + } + addrs = trimHostAddrList(addrs, maxOwnIdentifyMsgSize-usedSpace-256) // 256 bytes of buffer + snapshot := identifySnapshot{ addrs: addrs, protocols: protos, @@ -711,8 +752,16 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo }) } - // mes.ObservedAddr - ids.consumeObservedAddress(mes.GetObservedAddr(), c) + obsAddr, err := ma.NewMultiaddrBytes(mes.GetObservedAddr()) + if err != nil { + log.Debugf("error parsing received observed addr for %s: %s", c, err) + obsAddr = nil + } + + if obsAddr != nil && !ids.disableObservedAddrManager { + // TODO refactor this to use the emitted events instead of having this func call explicitly. + ids.observedAddrMgr.Record(c, obsAddr) + } // mes.ListenAddrs laddrs := mes.GetListenAddrs() @@ -746,7 +795,8 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo // Taking the lock ensures that we don't concurrently process a disconnect. ids.addrMu.Lock() ttl := peerstore.RecentlyConnectedAddrTTL - if ids.Host.Network().Connectedness(p) == network.Connected { + switch ids.Host.Network().Connectedness(p) { + case network.Limited, network.Connected: ttl = peerstore.ConnectedAddrTTL } @@ -763,13 +813,19 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo signedAddrs, err := ids.consumeSignedPeerRecord(c.RemotePeer(), signedPeerRecord) if err != nil { log.Debugf("failed to consume signed peer record: %s", err) + signedPeerRecord = nil } else { addrs = signedAddrs } } else { addrs = lmaddrs } - ids.Host.Peerstore().AddAddrs(p, filterAddrs(addrs, c.RemoteMultiaddr()), ttl) + addrs = filterAddrs(addrs, c.RemoteMultiaddr()) + if len(addrs) > connectedPeerMaxAddrs { + addrs = addrs[:connectedPeerMaxAddrs] + } + + ids.Host.Peerstore().AddAddrs(p, addrs, ttl) // Finally, expire all temporary addrs. ids.Host.Peerstore().UpdateAddrs(p, peerstore.TempAddrTTL, 0) @@ -786,6 +842,18 @@ func (ids *idService) consumeMessage(mes *pb.Identify, c network.Conn, isPush bo // get the key from the other side. we may not have it (no-auth transport) ids.consumeReceivedPubKey(c, mes.PublicKey) + + ids.emitters.evtPeerIdentificationCompleted.Emit(event.EvtPeerIdentificationCompleted{ + Peer: c.RemotePeer(), + Conn: c, + ListenAddrs: lmaddrs, + Protocols: mesProtocols, + SignedPeerRecord: signedPeerRecord, + ObservedAddr: obsAddr, + ProtocolVersion: pv, + AgentVersion: av, + }) + } func (ids *idService) consumeSignedPeerRecord(p peer.ID, signedPeerRecord *record.Envelope) ([]ma.Multiaddr, error) { @@ -919,20 +987,6 @@ func HasConsistentTransport(a ma.Multiaddr, green []ma.Multiaddr) bool { return false } -func (ids *idService) consumeObservedAddress(observed []byte, c network.Conn) { - if observed == nil { - return - } - - maddr, err := ma.NewMultiaddrBytes(observed) - if err != nil { - log.Debugf("error parsing received observed addr for %s: %s", c, err) - return - } - - ids.observedAddrs.Record(c, maddr) -} - // addConnWithLock assuems caller holds the connsMu lock func (ids *idService) addConnWithLock(c network.Conn) { _, found := ids.conns[c] @@ -975,13 +1029,36 @@ func (nn *netNotifiee) Disconnected(_ network.Network, c network.Conn) { delete(ids.conns, c) ids.connsMu.Unlock() - if ids.Host.Network().Connectedness(c.RemotePeer()) != network.Connected { - // Last disconnect. - // Undo the setting of addresses to peer.ConnectedAddrTTL we did - ids.addrMu.Lock() - defer ids.addrMu.Unlock() - ids.Host.Peerstore().UpdateAddrs(c.RemotePeer(), peerstore.ConnectedAddrTTL, peerstore.RecentlyConnectedAddrTTL) + if !ids.disableObservedAddrManager { + ids.observedAddrMgr.removeConn(c) } + + // Last disconnect. + // Undo the setting of addresses to peer.ConnectedAddrTTL we did + ids.addrMu.Lock() + defer ids.addrMu.Unlock() + + // This check MUST happen after acquiring the Lock as identify on a different connection + // might be trying to add addresses. + switch ids.Host.Network().Connectedness(c.RemotePeer()) { + case network.Connected, network.Limited: + return + } + // peerstore returns the elements in a random order as it uses a map to store the addresses + addrs := ids.Host.Peerstore().Addrs(c.RemotePeer()) + n := len(addrs) + if n > recentlyConnectedPeerMaxAddrs { + // We want to always save the address we are connected to + for i, a := range addrs { + if a.Equal(c.RemoteMultiaddr()) { + addrs[i], addrs[0] = addrs[0], addrs[i] + } + } + n = recentlyConnectedPeerMaxAddrs + } + ids.Host.Peerstore().UpdateAddrs(c.RemotePeer(), peerstore.ConnectedAddrTTL, peerstore.TempAddrTTL) + ids.Host.Peerstore().AddAddrs(c.RemotePeer(), addrs[:n], peerstore.RecentlyConnectedAddrTTL) + ids.Host.Peerstore().UpdateAddrs(c.RemotePeer(), peerstore.TempAddrTTL, 0) } func (nn *netNotifiee) Listen(n network.Network, a ma.Multiaddr) {} @@ -1000,3 +1077,55 @@ func filterAddrs(addrs []ma.Multiaddr, remote ma.Multiaddr) []ma.Multiaddr { } return ma.FilterAddrs(addrs, manet.IsPublicAddr) } + +func trimHostAddrList(addrs []ma.Multiaddr, maxSize int) []ma.Multiaddr { + totalSize := 0 + for _, a := range addrs { + totalSize += len(a.Bytes()) + } + if totalSize <= maxSize { + return addrs + } + + score := func(addr ma.Multiaddr) int { + var res int + if manet.IsPublicAddr(addr) { + res |= 1 << 12 + } else if !manet.IsIPLoopback(addr) { + res |= 1 << 11 + } + var protocolWeight int + ma.ForEach(addr, func(c ma.Component) bool { + switch c.Protocol().Code { + case ma.P_QUIC_V1: + protocolWeight = 5 + case ma.P_TCP: + protocolWeight = 4 + case ma.P_WSS: + protocolWeight = 3 + case ma.P_WEBTRANSPORT: + protocolWeight = 2 + case ma.P_WEBRTC_DIRECT: + protocolWeight = 1 + case ma.P_P2P: + return false + } + return true + }) + res |= 1 << protocolWeight + return res + } + + slices.SortStableFunc(addrs, func(a, b ma.Multiaddr) int { + return score(b) - score(a) // b-a for reverse order + }) + totalSize = 0 + for i, a := range addrs { + totalSize += len(a.Bytes()) + if totalSize > maxSize { + addrs = addrs[:i] + break + } + } + return addrs +} diff --git a/go-libp2p/p2p/protocol/identify/id_glass_test.go b/go-libp2p/p2p/protocol/identify/id_glass_test.go index 777cef0..3eec26c 100644 --- a/go-libp2p/p2p/protocol/identify/id_glass_test.go +++ b/go-libp2p/p2p/protocol/identify/id_glass_test.go @@ -12,6 +12,7 @@ import ( recordPb "github.com/libp2p/go-libp2p/core/record/pb" blhost "github.com/libp2p/go-libp2p/p2p/host/blank" swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" + ma "github.com/multiformats/go-multiaddr" "google.golang.org/protobuf/proto" "github.com/stretchr/testify/assert" @@ -173,3 +174,35 @@ func TestInvalidSignedPeerRecord(t *testing.T) { require.True(t, ok) require.Nil(t, cab.GetPeerRecord(h2.ID())) } + +func TestIncomingAddrFilter(t *testing.T) { + lhAddr := ma.StringCast("/ip4/127.0.0.1/udp/123/quic-v1") + privAddr := ma.StringCast("/ip4/192.168.1.101/tcp/123") + pubAddr := ma.StringCast("/ip6/2001::1/udp/123/quic-v1") + pubDNSAddr := ma.StringCast("/dns/example.com/udp/123/quic-v1") + privDNSAddr := ma.StringCast("/dns4/localhost/udp/123/quic-v1") + tests := []struct { + output []ma.Multiaddr + remote ma.Multiaddr + }{ + { + output: []ma.Multiaddr{lhAddr, privAddr, pubAddr, pubDNSAddr, privDNSAddr}, + remote: lhAddr, + }, + { + output: []ma.Multiaddr{privAddr, pubAddr, pubDNSAddr, privDNSAddr}, + remote: privAddr, + }, + { + output: []ma.Multiaddr{pubAddr, pubDNSAddr}, + remote: pubAddr, + }, + } + for _, tc := range tests { + t.Run(fmt.Sprintf("remote:%s", tc.remote), func(t *testing.T) { + input := []ma.Multiaddr{lhAddr, privAddr, pubAddr, pubDNSAddr, privDNSAddr} + got := filterAddrs(input, tc.remote) + require.ElementsMatch(t, tc.output, got, "%s\n%s", tc.output, got) + }) + } +} diff --git a/go-libp2p/p2p/protocol/identify/id_test.go b/go-libp2p/p2p/protocol/identify/id_test.go index b18ba51..a65d64f 100644 --- a/go-libp2p/p2p/protocol/identify/id_test.go +++ b/go-libp2p/p2p/protocol/identify/id_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "sync" "testing" "time" @@ -18,7 +19,6 @@ import ( "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/record" coretest "github.com/libp2p/go-libp2p/core/test" - basichost "github.com/libp2p/go-libp2p/p2p/host/basic" blhost "github.com/libp2p/go-libp2p/p2p/host/blank" "github.com/libp2p/go-libp2p/p2p/host/eventbus" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" @@ -107,101 +107,156 @@ func emitAddrChangeEvt(t *testing.T, h host.Host) { // this is because it used to be concurrent. Now, Dial wait till the // id service is done. func TestIDService(t *testing.T) { - // This test is highly timing dependent, waiting on timeouts/expiration. - oldTTL := peerstore.RecentlyConnectedAddrTTL - peerstore.RecentlyConnectedAddrTTL = 500 * time.Millisecond - t.Cleanup(func() { peerstore.RecentlyConnectedAddrTTL = oldTTL }) + for _, withObsAddrManager := range []bool{false, true} { + t.Run(fmt.Sprintf("withObsAddrManager=%t", withObsAddrManager), func(t *testing.T) { + if race.WithRace() { + t.Skip("This test modifies peerstore.RecentlyConnectedAddrTTL, which is racy.") + } + // This test is highly timing dependent, waiting on timeouts/expiration. + oldTTL := peerstore.RecentlyConnectedAddrTTL + oldTempTTL := peerstore.TempAddrTTL + peerstore.RecentlyConnectedAddrTTL = 500 * time.Millisecond + peerstore.TempAddrTTL = 50 * time.Millisecond + t.Cleanup(func() { + peerstore.RecentlyConnectedAddrTTL = oldTTL + peerstore.TempAddrTTL = oldTempTTL + }) - clk := mockClock.NewMock() - swarm1 := swarmt.GenSwarm(t, swarmt.WithClock(clk)) - swarm2 := swarmt.GenSwarm(t, swarmt.WithClock(clk)) - h1 := blhost.NewBlankHost(swarm1) - h2 := blhost.NewBlankHost(swarm2) + clk := mockClock.NewMock() + swarm1 := swarmt.GenSwarm(t, swarmt.WithClock(clk)) + swarm2 := swarmt.GenSwarm(t, swarmt.WithClock(clk)) + h1 := blhost.NewBlankHost(swarm1) + h2 := blhost.NewBlankHost(swarm2) - h1p := h1.ID() - h2p := h2.ID() + h1p := h1.ID() + h2p := h2.ID() - ids1, err := identify.NewIDService(h1) + opts := []identify.Option{} + if !withObsAddrManager { + opts = append(opts, identify.DisableObservedAddrManager()) + } + ids1, err := identify.NewIDService(h1, opts...) + require.NoError(t, err) + defer ids1.Close() + ids1.Start() + + opts = []identify.Option{} + if !withObsAddrManager { + opts = append(opts, identify.DisableObservedAddrManager()) + } + ids2, err := identify.NewIDService(h2, opts...) + require.NoError(t, err) + defer ids2.Close() + ids2.Start() + + sub, err := ids1.Host.EventBus().Subscribe(new(event.EvtPeerIdentificationCompleted)) + if err != nil { + t.Fatal(err) + } + + testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) // nothing + testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) // nothing + + // the forgetMe addr represents an address for h1 that h2 has learned out of band + // (not via identify protocol). During the identify exchange, it will be + // forgotten and replaced by the addrs h1 sends. + forgetMe, _ := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") + + h2.Peerstore().AddAddr(h1p, forgetMe, peerstore.RecentlyConnectedAddrTTL) + h2pi := h2.Peerstore().PeerInfo(h2p) + require.NoError(t, h1.Connect(context.Background(), h2pi)) + + h1t2c := h1.Network().ConnsToPeer(h2p) + require.NotEmpty(t, h1t2c, "should have a conn here") + + ids1.IdentifyConn(h1t2c[0]) + + // the idService should be opened automatically, by the network. + // what we should see now is that both peers know about each others listen addresses. + t.Log("test peer1 has peer2 addrs correctly") + testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them + testHasAgentVersion(t, h1, h2p) + testHasPublicKey(t, h1, h2p, h2.Peerstore().PubKey(h2p)) // h1 should have h2's public key + + // now, this wait we do have to do. it's the wait for the Listening side + // to be done identifying the connection. + c := h2.Network().ConnsToPeer(h1.ID()) + require.NotEmpty(t, c, "should have connection by now at least.") + ids2.IdentifyConn(c[0]) + + // and the protocol versions. + t.Log("test peer2 has peer1 addrs correctly") + testKnowsAddrs(t, h2, h1p, h1.Addrs()) // has them + testHasAgentVersion(t, h2, h1p) + testHasPublicKey(t, h2, h1p, h1.Peerstore().PubKey(h1p)) // h1 should have h2's public key + + // Need both sides to actually notice that the connection has been closed. + sentDisconnect1 := waitForDisconnectNotification(swarm1) + sentDisconnect2 := waitForDisconnectNotification(swarm2) + h1.Network().ClosePeer(h2p) + h2.Network().ClosePeer(h1p) + if len(h2.Network().ConnsToPeer(h1.ID())) != 0 || len(h1.Network().ConnsToPeer(h2.ID())) != 0 { + t.Fatal("should have no connections") + } + + t.Log("testing addrs just after disconnect") + // addresses don't immediately expire on disconnect, so we should still have them + testKnowsAddrs(t, h2, h1p, h1.Addrs()) + testKnowsAddrs(t, h1, h2p, h2.Addrs()) + + <-sentDisconnect1 + <-sentDisconnect2 + + // the addrs had their TTLs reduced on disconnect, and + // will be forgotten soon after + t.Log("testing addrs after TTL expiration") + clk.Add(time.Second) + testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) + testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) + + // test that we received the "identify completed" event. + select { + case evtAny := <-sub.Out(): + assertCorrectEvtPeerIdentificationCompleted(t, evtAny, h2) + case <-time.After(3 * time.Second): + t.Fatalf("expected EvtPeerIdentificationCompleted event within 10 seconds; none received") + } + }) + } +} + +func assertCorrectEvtPeerIdentificationCompleted(t *testing.T, evtAny interface{}, other host.Host) { + t.Helper() + evt := evtAny.(event.EvtPeerIdentificationCompleted) + require.NotNil(t, evt.Conn) + require.Equal(t, other.ID(), evt.Peer) + + require.Equal(t, len(other.Addrs()), len(evt.ListenAddrs)) + if len(other.Addrs()) == len(evt.ListenAddrs) { + otherAddrsStrings := make([]string, len(other.Addrs())) + evtAddrStrings := make([]string, len(evt.ListenAddrs)) + for i, a := range other.Addrs() { + otherAddrsStrings[i] = a.String() + evtAddrStrings[i] = evt.ListenAddrs[i].String() + } + slices.Sort(otherAddrsStrings) + slices.Sort(evtAddrStrings) + require.Equal(t, otherAddrsStrings, evtAddrStrings) + } + + otherProtos := other.Mux().Protocols() + slices.Sort(otherProtos) + evtProtos := evt.Protocols + slices.Sort(evtProtos) + require.Equal(t, otherProtos, evtProtos) + idFromSignedRecord, err := peer.IDFromPublicKey(evt.SignedPeerRecord.PublicKey) require.NoError(t, err) - defer ids1.Close() - ids1.Start() - - ids2, err := identify.NewIDService(h2) - require.NoError(t, err) - defer ids2.Close() - ids2.Start() - - sub, err := ids1.Host.EventBus().Subscribe(new(event.EvtPeerIdentificationCompleted)) - if err != nil { - t.Fatal(err) - } - - testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) // nothing - testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) // nothing - - // the forgetMe addr represents an address for h1 that h2 has learned out of band - // (not via identify protocol). During the identify exchange, it will be - // forgotten and replaced by the addrs h1 sends. - forgetMe, _ := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") - - h2.Peerstore().AddAddr(h1p, forgetMe, peerstore.RecentlyConnectedAddrTTL) - h2pi := h2.Peerstore().PeerInfo(h2p) - require.NoError(t, h1.Connect(context.Background(), h2pi)) - - h1t2c := h1.Network().ConnsToPeer(h2p) - require.NotEmpty(t, h1t2c, "should have a conn here") - - ids1.IdentifyConn(h1t2c[0]) - - // the idService should be opened automatically, by the network. - // what we should see now is that both peers know about each others listen addresses. - t.Log("test peer1 has peer2 addrs correctly") - testKnowsAddrs(t, h1, h2p, h2.Addrs()) // has them - testHasAgentVersion(t, h1, h2p) - testHasPublicKey(t, h1, h2p, h2.Peerstore().PubKey(h2p)) // h1 should have h2's public key - - // now, this wait we do have to do. it's the wait for the Listening side - // to be done identifying the connection. - c := h2.Network().ConnsToPeer(h1.ID()) - require.NotEmpty(t, c, "should have connection by now at least.") - ids2.IdentifyConn(c[0]) - - // and the protocol versions. - t.Log("test peer2 has peer1 addrs correctly") - testKnowsAddrs(t, h2, h1p, h1.Addrs()) // has them - testHasAgentVersion(t, h2, h1p) - testHasPublicKey(t, h2, h1p, h1.Peerstore().PubKey(h1p)) // h1 should have h2's public key - - // Need both sides to actually notice that the connection has been closed. - sentDisconnect1 := waitForDisconnectNotification(swarm1) - sentDisconnect2 := waitForDisconnectNotification(swarm2) - h1.Network().ClosePeer(h2p) - h2.Network().ClosePeer(h1p) - if len(h2.Network().ConnsToPeer(h1.ID())) != 0 || len(h1.Network().ConnsToPeer(h2.ID())) != 0 { - t.Fatal("should have no connections") - } - - t.Log("testing addrs just after disconnect") - // addresses don't immediately expire on disconnect, so we should still have them - testKnowsAddrs(t, h2, h1p, h1.Addrs()) - testKnowsAddrs(t, h1, h2p, h2.Addrs()) - - <-sentDisconnect1 - <-sentDisconnect2 - - // the addrs had their TTLs reduced on disconnect, and - // will be forgotten soon after - t.Log("testing addrs after TTL expiration") - clk.Add(time.Second) - testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) - testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) - - // test that we received the "identify completed" event. - select { - case <-sub.Out(): - case <-time.After(3 * time.Second): - t.Fatalf("expected EvtPeerIdentificationCompleted event within 10 seconds; none received") - } + require.Equal(t, other.ID(), idFromSignedRecord) + require.Equal(t, peer.PeerRecordEnvelopePayloadType, evt.SignedPeerRecord.PayloadType) + var peerRecord peer.PeerRecord + evt.SignedPeerRecord.TypedRecord(&peerRecord) + require.Equal(t, other.ID(), peerRecord.PeerID) + require.Equal(t, other.Addrs(), peerRecord.Addrs) } func TestProtoMatching(t *testing.T) { @@ -565,8 +620,13 @@ func TestLargeIdentifyMessage(t *testing.T) { t.Skip("setting peerstore.RecentlyConnectedAddrTTL is racy") } oldTTL := peerstore.RecentlyConnectedAddrTTL + oldTempTTL := peerstore.TempAddrTTL peerstore.RecentlyConnectedAddrTTL = 500 * time.Millisecond - t.Cleanup(func() { peerstore.RecentlyConnectedAddrTTL = oldTTL }) + peerstore.TempAddrTTL = 50 * time.Millisecond + t.Cleanup(func() { + peerstore.RecentlyConnectedAddrTTL = oldTTL + peerstore.TempAddrTTL = oldTempTTL + }) clk := mockClock.NewMock() swarm1 := swarmt.GenSwarm(t, swarmt.WithClock(clk)) @@ -612,7 +672,7 @@ func TestLargeIdentifyMessage(t *testing.T) { require.NoError(t, h1.Connect(context.Background(), h2pi)) h1t2c := h1.Network().ConnsToPeer(h2p) - require.Equal(t, 1, len(h1t2c), "should have a conn here") + require.Len(t, h1t2c, 1, "should have a conn here") ids1.IdentifyConn(h1t2c[0]) @@ -663,7 +723,8 @@ func TestLargeIdentifyMessage(t *testing.T) { // test that we received the "identify completed" event. select { - case <-sub.Out(): + case evtAny := <-sub.Out(): + assertCorrectEvtPeerIdentificationCompleted(t, evtAny, h2) case <-time.After(3 * time.Second): t.Fatalf("expected EvtPeerIdentificationCompleted event within 3 seconds; none received") } @@ -841,8 +902,10 @@ func TestIncomingIDStreamsTimeout(t *testing.T) { func TestOutOfOrderConnectedNotifs(t *testing.T) { h1, err := libp2p.New(libp2p.NoListenAddrs) require.NoError(t, err) + defer h1.Close() h2, err := libp2p.New(libp2p.ListenAddrs(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"))) require.NoError(t, err) + defer h2.Close() doneCh := make(chan struct{}) errCh := make(chan error) @@ -850,11 +913,10 @@ func TestOutOfOrderConnectedNotifs(t *testing.T) { // This callback may be called before identify's Connnected callback completes. If it does, the IdentifyWait should still finish successfully. h1.Network().Notify(&network.NotifyBundle{ ConnectedF: func(n network.Network, c network.Conn) { - bh1 := h1.(*basichost.BasicHost) - idChan := bh1.IDService().IdentifyWait(c) + idChan := h1.(interface{ IDService() identify.IDService }).IDService().IdentifyWait(c) go func() { <-idChan - protos, err := bh1.Peerstore().GetProtocols(h2.ID()) + protos, err := h1.Peerstore().GetProtocols(h2.ID()) if err != nil { errCh <- err } diff --git a/go-libp2p/p2p/protocol/identify/nat_emitter.go b/go-libp2p/p2p/protocol/identify/nat_emitter.go new file mode 100644 index 0000000..fec9b68 --- /dev/null +++ b/go-libp2p/p2p/protocol/identify/nat_emitter.go @@ -0,0 +1,119 @@ +package identify + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/libp2p/go-libp2p/core/event" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/p2p/host/eventbus" +) + +type natEmitter struct { + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup + reachabilitySub event.Subscription + reachability network.Reachability + eventInterval time.Duration + + currentUDPNATDeviceType network.NATDeviceType + currentTCPNATDeviceType network.NATDeviceType + emitNATDeviceTypeChanged event.Emitter + + observedAddrMgr *ObservedAddrManager +} + +func newNATEmitter(h host.Host, o *ObservedAddrManager, eventInterval time.Duration) (*natEmitter, error) { + ctx, cancel := context.WithCancel(context.Background()) + n := &natEmitter{ + observedAddrMgr: o, + ctx: ctx, + cancel: cancel, + eventInterval: eventInterval, + } + reachabilitySub, err := h.EventBus().Subscribe(new(event.EvtLocalReachabilityChanged), eventbus.Name("identify (nat emitter)")) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to reachability event: %s", err) + } + n.reachabilitySub = reachabilitySub + + emitter, err := h.EventBus().Emitter(new(event.EvtNATDeviceTypeChanged), eventbus.Stateful) + if err != nil { + return nil, fmt.Errorf("failed to create emitter for NATDeviceType: %s", err) + } + n.emitNATDeviceTypeChanged = emitter + + n.wg.Add(1) + go n.worker() + return n, nil +} + +func (n *natEmitter) worker() { + defer n.wg.Done() + subCh := n.reachabilitySub.Out() + ticker := time.NewTicker(n.eventInterval) + pendingUpdate := false + enoughTimeSinceLastUpdate := true + for { + select { + case evt, ok := <-subCh: + if !ok { + subCh = nil + continue + } + ev, ok := evt.(event.EvtLocalReachabilityChanged) + if !ok { + log.Error("invalid event: %v", evt) + continue + } + n.reachability = ev.Reachability + case <-ticker.C: + enoughTimeSinceLastUpdate = true + if pendingUpdate { + n.maybeNotify() + pendingUpdate = false + enoughTimeSinceLastUpdate = false + } + case <-n.observedAddrMgr.addrRecordedNotif: + pendingUpdate = true + if enoughTimeSinceLastUpdate { + n.maybeNotify() + pendingUpdate = false + enoughTimeSinceLastUpdate = false + } + case <-n.ctx.Done(): + return + } + } +} + +func (n *natEmitter) maybeNotify() { + if n.reachability == network.ReachabilityPrivate { + tcpNATType, udpNATType := n.observedAddrMgr.getNATType() + if tcpNATType != n.currentTCPNATDeviceType { + n.currentTCPNATDeviceType = tcpNATType + n.emitNATDeviceTypeChanged.Emit(event.EvtNATDeviceTypeChanged{ + TransportProtocol: network.NATTransportTCP, + NatDeviceType: n.currentTCPNATDeviceType, + }) + } + if udpNATType != n.currentUDPNATDeviceType { + n.currentUDPNATDeviceType = udpNATType + n.emitNATDeviceTypeChanged.Emit(event.EvtNATDeviceTypeChanged{ + TransportProtocol: network.NATTransportUDP, + NatDeviceType: n.currentUDPNATDeviceType, + }) + } + } +} + +func (n *natEmitter) Close() { + n.cancel() + n.wg.Wait() + n.reachabilitySub.Close() + n.emitNATDeviceTypeChanged.Close() +} diff --git a/go-libp2p/p2p/protocol/identify/obsaddr.go b/go-libp2p/p2p/protocol/identify/obsaddr.go index 3466c56..4437c4b 100644 --- a/go-libp2p/p2p/protocol/identify/obsaddr.go +++ b/go-libp2p/p2p/protocol/identify/obsaddr.go @@ -3,16 +3,12 @@ package identify import ( "context" "fmt" + "net" + "slices" + "sort" "sync" - "time" - "golang.org/x/exp/slices" - - "github.com/libp2p/go-libp2p/core/event" - "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peerstore" - "github.com/libp2p/go-libp2p/p2p/host/eventbus" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" @@ -25,214 +21,252 @@ import ( // the GC rounds set by GCInterval. var ActivationThresh = 4 -// GCInterval specicies how often to make a round cleaning seen events and -// observed addresses. An address will be cleaned if it has not been seen in -// OwnObservedAddressTTL (10 minutes). A "seen" event will be cleaned up if -// it is older than OwnObservedAddressTTL * ActivationThresh (40 minutes). -var GCInterval = 10 * time.Minute - // observedAddrManagerWorkerChannelSize defines how many addresses can be enqueued // for adding to an ObservedAddrManager. var observedAddrManagerWorkerChannelSize = 16 -// maxObservedAddrsPerIPAndTransport is the maximum number of observed addresses -// we will return for each (IPx/TCP or UDP) group. -var maxObservedAddrsPerIPAndTransport = 2 +const maxExternalThinWaistAddrsPerLocalAddr = 3 -// observation records an address observation from an "observer" (where every IP -// address is a unique observer). -type observation struct { - // seenTime is the last time this observation was made. - seenTime time.Time - // inbound indicates whether or not this observation has been made from - // an inbound connection. This remains true even if we an observation - // from a subsequent outbound connection. - inbound bool +// thinWaist is a struct that stores the address along with it's thin waist prefix and rest of the multiaddr +type thinWaist struct { + Addr, TW, Rest ma.Multiaddr } -// observedAddr is an entry for an address reported by our peers. -// We only use addresses that: -// - have been observed at least 4 times in last 40 minutes. (counter symmetric nats) -// - have been observed at least once recently (10 minutes), because our position in the -// network, or network port mapppings, may have changed. -type observedAddr struct { - addr ma.Multiaddr - seenBy map[string]observation // peer(observer) address -> observation info - lastSeen time.Time - numInbound int +// thinWaistWithCount is a thinWaist along with the count of the connection that have it as the local address +type thinWaistWithCount struct { + thinWaist + Count int } -func (oa *observedAddr) activated() bool { - - // We only activate if other peers observed the same address - // of ours at least 4 times. SeenBy peers are removed by GC if - // they say the address more than ttl*ActivationThresh - return len(oa.seenBy) >= ActivationThresh -} - -// GroupKey returns the group in which this observation belongs. Currently, an -// observed address's group is just the address with all ports set to 0. This -// means we can advertise the most commonly observed external ports without -// advertising _every_ observed port. -func (oa *observedAddr) groupKey() string { - key := make([]byte, 0, len(oa.addr.Bytes())) - ma.ForEach(oa.addr, func(c ma.Component) bool { - switch proto := c.Protocol(); proto.Code { - case ma.P_TCP, ma.P_UDP: - key = append(key, proto.VCode...) - key = append(key, 0, 0) // zero in two bytes - default: - key = append(key, c.Bytes()...) +func thinWaistForm(a ma.Multiaddr) (thinWaist, error) { + i := 0 + tw, rest := ma.SplitFunc(a, func(c ma.Component) bool { + if i > 1 { + return true } - return true + switch i { + case 0: + if c.Protocol().Code == ma.P_IP4 || c.Protocol().Code == ma.P_IP6 { + i++ + return false + } + return true + case 1: + if c.Protocol().Code == ma.P_TCP || c.Protocol().Code == ma.P_UDP { + i++ + return false + } + return true + } + return false }) - - return string(key) + if i <= 1 { + return thinWaist{}, fmt.Errorf("not a thinwaist address: %s", a) + } + return thinWaist{Addr: a, TW: tw, Rest: rest}, nil } -type newObservation struct { - conn network.Conn +// getObserver returns the observer for the multiaddress +// For an IPv4 multiaddress the observer is the IP address +// For an IPv6 multiaddress the observer is the first /56 prefix of the IP address +func getObserver(a ma.Multiaddr) (string, error) { + ip, err := manet.ToIP(a) + if err != nil { + return "", err + } + if ip4 := ip.To4(); ip4 != nil { + return ip4.String(), nil + } + // Count /56 prefix as a single observer. + return ip.Mask(net.CIDRMask(56, 128)).String(), nil +} + +// connMultiaddrs provides IsClosed along with network.ConnMultiaddrs. It is easier to mock this than network.Conn +type connMultiaddrs interface { + network.ConnMultiaddrs + IsClosed() bool +} + +// observerSetCacheSize is the number of transport sharing the same thinwaist (tcp, ws, wss), (quic, webtransport, webrtc-direct) +// This is 3 in practice right now, but keep a buffer of 3 extra elements +const observerSetCacheSize = 5 + +// observerSet is the set of observers who have observed ThinWaistAddr +type observerSet struct { + ObservedTWAddr ma.Multiaddr + ObservedBy map[string]int + + mu sync.RWMutex // protects following + cachedMultiaddrs map[string]ma.Multiaddr // cache of localMultiaddr rest(addr - thinwaist) => output multiaddr +} + +func (s *observerSet) cacheMultiaddr(addr ma.Multiaddr) ma.Multiaddr { + if addr == nil { + return s.ObservedTWAddr + } + addrStr := string(addr.Bytes()) + s.mu.RLock() + res, ok := s.cachedMultiaddrs[addrStr] + s.mu.RUnlock() + if ok { + return res + } + + s.mu.Lock() + defer s.mu.Unlock() + // Check if some other go routine added this while we were waiting + res, ok = s.cachedMultiaddrs[addrStr] + if ok { + return res + } + if s.cachedMultiaddrs == nil { + s.cachedMultiaddrs = make(map[string]ma.Multiaddr, observerSetCacheSize) + } + if len(s.cachedMultiaddrs) == observerSetCacheSize { + // remove one entry if we will go over the limit + for k := range s.cachedMultiaddrs { + delete(s.cachedMultiaddrs, k) + break + } + } + s.cachedMultiaddrs[addrStr] = ma.Join(s.ObservedTWAddr, addr) + return s.cachedMultiaddrs[addrStr] +} + +type observation struct { + conn connMultiaddrs observed ma.Multiaddr } -// ObservedAddrManager keeps track of a ObservedAddrs. +// ObservedAddrManager maps connection's local multiaddrs to their externally observable multiaddress type ObservedAddrManager struct { - host host.Host + // Our listen addrs + listenAddrs func() []ma.Multiaddr + // Our listen addrs with interface addrs for unspecified addrs + interfaceListenAddrs func() ([]ma.Multiaddr, error) + // All host addrs + hostAddrs func() []ma.Multiaddr + // Any normalization required before comparing. Useful to remove certhash + normalize func(ma.Multiaddr) ma.Multiaddr + // worker channel for new observations + wch chan observation + // notified on recording an observation + addrRecordedNotif chan struct{} - closeOnce sync.Once - refCount sync.WaitGroup - ctx context.Context // the context is canceled when Close is called + // for closing + wg sync.WaitGroup + ctx context.Context ctxCancel context.CancelFunc - // latest observation from active connections - // we'll "re-observe" these when we gc - activeConnsMu sync.Mutex - // active connection -> most recent observation - activeConns map[network.Conn]ma.Multiaddr - - mu sync.RWMutex - closed bool - // local(internal) address -> list of observed(external) addresses - addrs map[string][]*observedAddr - ttl time.Duration - refreshTimer *time.Timer - - // this is the worker channel - wch chan newObservation - - reachabilitySub event.Subscription - reachability network.Reachability - - currentUDPNATDeviceType network.NATDeviceType - currentTCPNATDeviceType network.NATDeviceType - emitNATDeviceTypeChanged event.Emitter + mu sync.RWMutex + // local thin waist => external thin waist => observerSet + externalAddrs map[string]map[string]*observerSet + // connObservedTWAddrs maps the connection to the last observed thin waist multiaddr on that connection + connObservedTWAddrs map[connMultiaddrs]ma.Multiaddr + // localMultiaddr => thin waist form with the count of the connections the multiaddr + // was seen on for tracking our local listen addresses + localAddrs map[string]*thinWaistWithCount } -// NewObservedAddrManager returns a new address manager using -// peerstore.OwnObservedAddressTTL as the TTL. -func NewObservedAddrManager(host host.Host) (*ObservedAddrManager, error) { - oas := &ObservedAddrManager{ - addrs: make(map[string][]*observedAddr), - ttl: peerstore.OwnObservedAddrTTL, - wch: make(chan newObservation, observedAddrManagerWorkerChannelSize), - host: host, - activeConns: make(map[network.Conn]ma.Multiaddr), - // refresh every ttl/2 so we don't forget observations from connected peers - refreshTimer: time.NewTimer(peerstore.OwnObservedAddrTTL / 2), +// NewObservedAddrManager returns a new address manager using peerstore.OwnObservedAddressTTL as the TTL. +func NewObservedAddrManager(listenAddrs, hostAddrs func() []ma.Multiaddr, + interfaceListenAddrs func() ([]ma.Multiaddr, error), normalize func(ma.Multiaddr) ma.Multiaddr) (*ObservedAddrManager, error) { + if normalize == nil { + normalize = func(addr ma.Multiaddr) ma.Multiaddr { return addr } } - oas.ctx, oas.ctxCancel = context.WithCancel(context.Background()) - - reachabilitySub, err := host.EventBus().Subscribe(new(event.EvtLocalReachabilityChanged), eventbus.Name("identify (obsaddr)")) - if err != nil { - return nil, fmt.Errorf("failed to subscribe to reachability event: %s", err) + o := &ObservedAddrManager{ + externalAddrs: make(map[string]map[string]*observerSet), + connObservedTWAddrs: make(map[connMultiaddrs]ma.Multiaddr), + localAddrs: make(map[string]*thinWaistWithCount), + wch: make(chan observation, observedAddrManagerWorkerChannelSize), + addrRecordedNotif: make(chan struct{}, 1), + listenAddrs: listenAddrs, + interfaceListenAddrs: interfaceListenAddrs, + hostAddrs: hostAddrs, + normalize: normalize, } - oas.reachabilitySub = reachabilitySub + o.ctx, o.ctxCancel = context.WithCancel(context.Background()) - emitter, err := host.EventBus().Emitter(new(event.EvtNATDeviceTypeChanged), eventbus.Stateful) - if err != nil { - return nil, fmt.Errorf("failed to create emitter for NATDeviceType: %s", err) - } - oas.emitNATDeviceTypeChanged = emitter - - oas.host.Network().Notify((*obsAddrNotifiee)(oas)) - oas.refCount.Add(1) - go oas.worker() - return oas, nil + o.wg.Add(1) + go o.worker() + return o, nil } // AddrsFor return all activated observed addresses associated with the given // (resolved) listen address. -func (oas *ObservedAddrManager) AddrsFor(addr ma.Multiaddr) (addrs []ma.Multiaddr) { - oas.mu.RLock() - defer oas.mu.RUnlock() - - if len(oas.addrs) == 0 { +func (o *ObservedAddrManager) AddrsFor(addr ma.Multiaddr) (addrs []ma.Multiaddr) { + if addr == nil { + return nil + } + o.mu.RLock() + defer o.mu.RUnlock() + tw, err := thinWaistForm(o.normalize(addr)) + if err != nil { return nil } - observedAddrs, ok := oas.addrs[string(addr.Bytes())] - if !ok { - return + observerSets := o.getTopExternalAddrs(string(tw.TW.Bytes())) + res := make([]ma.Multiaddr, 0, len(observerSets)) + for _, s := range observerSets { + res = append(res, s.cacheMultiaddr(tw.Rest)) } - - return oas.filter(observedAddrs) + return res } // Addrs return all activated observed addresses -func (oas *ObservedAddrManager) Addrs() []ma.Multiaddr { - oas.mu.RLock() - defer oas.mu.RUnlock() +func (o *ObservedAddrManager) Addrs() []ma.Multiaddr { + o.mu.RLock() + defer o.mu.RUnlock() - if len(oas.addrs) == 0 { - return nil + m := make(map[string][]*observerSet) + for localTWStr := range o.externalAddrs { + m[localTWStr] = append(m[localTWStr], o.getTopExternalAddrs(localTWStr)...) } - - var allObserved []*observedAddr - for _, addrs := range oas.addrs { - allObserved = append(allObserved, addrs...) - } - return oas.filter(allObserved) -} - -func (oas *ObservedAddrManager) filter(observedAddrs []*observedAddr) []ma.Multiaddr { - pmap := make(map[string][]*observedAddr) - now := time.Now() - - for i := range observedAddrs { - a := observedAddrs[i] - if now.Sub(a.lastSeen) <= oas.ttl && a.activated() { - // group addresses by their IPX/Transport Protocol(TCP or UDP) pattern. - pat := a.groupKey() - pmap[pat] = append(pmap[pat], a) - + addrs := make([]ma.Multiaddr, 0, maxExternalThinWaistAddrsPerLocalAddr*5) // assume 5 transports + for _, t := range o.localAddrs { + for _, s := range m[string(t.TW.Bytes())] { + addrs = append(addrs, s.cacheMultiaddr(t.Rest)) } } - - addrs := make([]ma.Multiaddr, 0, len(observedAddrs)) - for pat := range pmap { - s := pmap[pat] - - // We prefer inbound connection observations over outbound. - // For ties, we prefer the ones with more votes. - slices.SortFunc(s, func(first, second *observedAddr) int { - if first.numInbound > second.numInbound { - return 1 - } - return len(first.seenBy) - len(second.seenBy) - }) - - for i := 0; i < maxObservedAddrsPerIPAndTransport && i < len(s); i++ { - addrs = append(addrs, s[i].addr) - } - } - return addrs } -// Record records an address observation, if valid. -func (oas *ObservedAddrManager) Record(conn network.Conn, observed ma.Multiaddr) { +func (o *ObservedAddrManager) getTopExternalAddrs(localTWStr string) []*observerSet { + observerSets := make([]*observerSet, 0, len(o.externalAddrs[localTWStr])) + for _, v := range o.externalAddrs[localTWStr] { + if len(v.ObservedBy) >= ActivationThresh { + observerSets = append(observerSets, v) + } + } + slices.SortFunc(observerSets, func(a, b *observerSet) int { + diff := len(b.ObservedBy) - len(a.ObservedBy) + if diff != 0 { + return diff + } + // In case we have elements with equal counts, + // keep the address list stable by using the lexicographically smaller address + as := a.ObservedTWAddr.String() + bs := b.ObservedTWAddr.String() + if as < bs { + return -1 + } else if as > bs { + return 1 + } else { + return 0 + } + + }) + n := len(observerSets) + if n > maxExternalThinWaistAddrsPerLocalAddr { + n = maxExternalThinWaistAddrsPerLocalAddr + } + return observerSets[:n] +} + +// Record enqueues an observation for recording +func (o *ObservedAddrManager) Record(conn connMultiaddrs, observed ma.Multiaddr) { select { - case oas.wch <- newObservation{ + case o.wch <- observation{ conn: conn, observed: observed, }: @@ -244,182 +278,72 @@ func (oas *ObservedAddrManager) Record(conn network.Conn, observed ma.Multiaddr) } } -func (oas *ObservedAddrManager) worker() { - defer oas.refCount.Done() +func (o *ObservedAddrManager) worker() { + defer o.wg.Done() - ticker := time.NewTicker(GCInterval) - defer ticker.Stop() - - subChan := oas.reachabilitySub.Out() for { select { - case evt, ok := <-subChan: - if !ok { - subChan = nil - continue - } - ev := evt.(event.EvtLocalReachabilityChanged) - oas.reachability = ev.Reachability - case obs := <-oas.wch: - oas.maybeRecordObservation(obs.conn, obs.observed) - case <-ticker.C: - oas.gc() - case <-oas.refreshTimer.C: - oas.refresh() - case <-oas.ctx.Done(): + case obs := <-o.wch: + o.maybeRecordObservation(obs.conn, obs.observed) + case <-o.ctx.Done(): return } } } -func (oas *ObservedAddrManager) refresh() { - oas.activeConnsMu.Lock() - recycledObservations := make([]newObservation, 0, len(oas.activeConns)) - for conn, observed := range oas.activeConns { - recycledObservations = append(recycledObservations, newObservation{ - conn: conn, - observed: observed, - }) +func (o *ObservedAddrManager) shouldRecordObservation(conn connMultiaddrs, observed ma.Multiaddr) (shouldRecord bool, localTW thinWaist, observedTW thinWaist) { + if conn == nil || observed == nil { + return false, thinWaist{}, thinWaist{} } - oas.activeConnsMu.Unlock() - - oas.mu.Lock() - defer oas.mu.Unlock() - for _, obs := range recycledObservations { - oas.recordObservationUnlocked(obs.conn, obs.observed) - } - // refresh every ttl/2 so we don't forget observations from connected peers - oas.refreshTimer.Reset(oas.ttl / 2) -} - -func (oas *ObservedAddrManager) gc() { - oas.mu.Lock() - defer oas.mu.Unlock() - - now := time.Now() - for local, observedAddrs := range oas.addrs { - filteredAddrs := observedAddrs[:0] - for _, a := range observedAddrs { - // clean up SeenBy set - for k, ob := range a.seenBy { - if now.Sub(ob.seenTime) > oas.ttl*time.Duration(ActivationThresh) { - delete(a.seenBy, k) - if ob.inbound { - a.numInbound-- - } - } - } - - // leave only alive observed addresses - if now.Sub(a.lastSeen) <= oas.ttl { - filteredAddrs = append(filteredAddrs, a) - } - } - if len(filteredAddrs) > 0 { - oas.addrs[local] = filteredAddrs - } else { - delete(oas.addrs, local) - } - } -} - -func (oas *ObservedAddrManager) addConn(conn network.Conn, observed ma.Multiaddr) { - oas.activeConnsMu.Lock() - defer oas.activeConnsMu.Unlock() - - // We need to make sure we haven't received a disconnect event for this - // connection yet. The only way to do that right now is to make sure the - // swarm still has the connection. - // - // Doing this under a lock that we _also_ take in a disconnect event - // handler ensures everything happens in the right order. - for _, c := range oas.host.Network().ConnsToPeer(conn.RemotePeer()) { - if c == conn { - oas.activeConns[conn] = observed - return - } - } -} - -func (oas *ObservedAddrManager) removeConn(conn network.Conn) { - // DO NOT remove this lock. - // This ensures we don't call addConn at the same time: - // 1. see that we have a connection and pause inside addConn right before recording it. - // 2. process a disconnect event. - // 3. record the connection (leaking it). - - oas.activeConnsMu.Lock() - delete(oas.activeConns, conn) - oas.activeConnsMu.Unlock() -} - -type normalizeMultiaddrer interface { - NormalizeMultiaddr(addr ma.Multiaddr) ma.Multiaddr -} - -type addrsProvider interface { - Addrs() []ma.Multiaddr -} - -type listenAddrsProvider interface { - ListenAddresses() []ma.Multiaddr - InterfaceListenAddresses() ([]ma.Multiaddr, error) -} - -func shouldRecordObservation(host addrsProvider, network listenAddrsProvider, conn network.ConnMultiaddrs, observed ma.Multiaddr) bool { - // First, determine if this observation is even worth keeping... - // Ignore observations from loopback nodes. We already know our loopback // addresses. if manet.IsIPLoopback(observed) { - return false + return false, thinWaist{}, thinWaist{} } // Provided by NAT64 peers, these addresses are specific to the peer and not publicly routable if manet.IsNAT64IPv4ConvertedIPv6Addr(observed) { - return false + return false, thinWaist{}, thinWaist{} } // we should only use ObservedAddr when our connection's LocalAddr is one // of our ListenAddrs. If we Dial out using an ephemeral addr, knowing that // address's external mapping is not very useful because the port will not be // the same as the listen addr. - ifaceaddrs, err := network.InterfaceListenAddresses() + ifaceaddrs, err := o.interfaceListenAddrs() if err != nil { log.Infof("failed to get interface listen addrs", err) - return false + return false, thinWaist{}, thinWaist{} } - normalizer, canNormalize := host.(normalizeMultiaddrer) - - if canNormalize { - for i, a := range ifaceaddrs { - ifaceaddrs[i] = normalizer.NormalizeMultiaddr(a) - } + for i, a := range ifaceaddrs { + ifaceaddrs[i] = o.normalize(a) } - local := conn.LocalMultiaddr() - if canNormalize { - local = normalizer.NormalizeMultiaddr(local) - } + local := o.normalize(conn.LocalMultiaddr()) - listenAddrs := network.ListenAddresses() - if canNormalize { - for i, a := range listenAddrs { - listenAddrs[i] = normalizer.NormalizeMultiaddr(a) - } + listenAddrs := o.listenAddrs() + for i, a := range listenAddrs { + listenAddrs[i] = o.normalize(a) } if !ma.Contains(ifaceaddrs, local) && !ma.Contains(listenAddrs, local) { // not in our list - return false + return false, thinWaist{}, thinWaist{} } - hostAddrs := host.Addrs() - if canNormalize { - for i, a := range hostAddrs { - hostAddrs[i] = normalizer.NormalizeMultiaddr(a) - } + localTW, err = thinWaistForm(local) + if err != nil { + return false, thinWaist{}, thinWaist{} + } + observedTW, err = thinWaistForm(o.normalize(observed)) + if err != nil { + return false, thinWaist{}, thinWaist{} + } + + hostAddrs := o.hostAddrs() + for i, a := range hostAddrs { + hostAddrs[i] = o.normalize(a) } // We should reject the connection if the observation doesn't match the @@ -431,207 +355,192 @@ func shouldRecordObservation(host addrsProvider, network listenAddrsProvider, co "from", conn.RemoteMultiaddr(), "observed", observed, ) - return false + return false, thinWaist{}, thinWaist{} } - return true + return true, localTW, observedTW } -func (oas *ObservedAddrManager) maybeRecordObservation(conn network.Conn, observed ma.Multiaddr) { - shouldRecord := shouldRecordObservation(oas.host, oas.host.Network(), conn, observed) - if shouldRecord { - // Ok, the observation is good, record it. - log.Debugw("added own observed listen addr", "observed", observed) - defer oas.addConn(conn, observed) - - oas.mu.Lock() - defer oas.mu.Unlock() - oas.recordObservationUnlocked(conn, observed) - - if oas.reachability == network.ReachabilityPrivate { - oas.emitAllNATTypes() - } - } -} - -func (oas *ObservedAddrManager) recordObservationUnlocked(conn network.Conn, observed ma.Multiaddr) { - now := time.Now() - observerString := observerGroup(conn.RemoteMultiaddr()) - localString := string(conn.LocalMultiaddr().Bytes()) - ob := observation{ - seenTime: now, - inbound: conn.Stat().Direction == network.DirInbound, - } - - // check if observed address seen yet, if so, update it - for _, observedAddr := range oas.addrs[localString] { - if observedAddr.addr.Equal(observed) { - // Don't trump an outbound observation with an inbound - // one. - wasInbound := observedAddr.seenBy[observerString].inbound - isInbound := ob.inbound - ob.inbound = isInbound || wasInbound - - if !wasInbound && isInbound { - observedAddr.numInbound++ - } - - observedAddr.seenBy[observerString] = ob - observedAddr.lastSeen = now - return - } - } - - // observed address not seen yet, append it - oa := &observedAddr{ - addr: observed, - seenBy: map[string]observation{ - observerString: ob, - }, - lastSeen: now, - } - if ob.inbound { - oa.numInbound++ - } - oas.addrs[localString] = append(oas.addrs[localString], oa) -} - -// For a given transport Protocol (TCP/UDP): -// -// 1. If we have an activated address, we are behind an Cone NAT. -// With regards to RFC 3489, this could be either a Full Cone NAT, a Restricted Cone NAT or a -// Port Restricted Cone NAT. However, we do NOT differentiate between them here and simply classify all such NATs as a Cone NAT. -// -// 2. If four different peers observe a different address for us on outbound connections, we -// are MOST probably behind a Symmetric NAT. -// -// Please see the documentation on the enumerations for `network.NATDeviceType` for more details about these NAT Device types -// and how they relate to NAT traversal via Hole Punching. -func (oas *ObservedAddrManager) emitAllNATTypes() { - var allObserved []*observedAddr - for _, addrs := range oas.addrs { - allObserved = append(allObserved, addrs...) - } - - hasChanged, natType := oas.emitSpecificNATType(allObserved, ma.P_TCP, network.NATTransportTCP, oas.currentTCPNATDeviceType) - if hasChanged { - oas.currentTCPNATDeviceType = natType - } - - hasChanged, natType = oas.emitSpecificNATType(allObserved, ma.P_UDP, network.NATTransportUDP, oas.currentUDPNATDeviceType) - if hasChanged { - oas.currentUDPNATDeviceType = natType - } -} - -// returns true along with the new NAT device type if the NAT device type for the given protocol has changed. -// returns false otherwise. -func (oas *ObservedAddrManager) emitSpecificNATType(addrs []*observedAddr, protoCode int, transportProto network.NATTransportProtocol, - currentNATType network.NATDeviceType) (bool, network.NATDeviceType) { - now := time.Now() - seenBy := make(map[string]struct{}) - cnt := 0 - - for _, oa := range addrs { - _, err := oa.addr.ValueForProtocol(protoCode) - if err != nil { - continue - } - - // if we have an activated addresses, it's a Cone NAT. - if now.Sub(oa.lastSeen) <= oas.ttl && oa.activated() { - if currentNATType != network.NATDeviceTypeCone { - oas.emitNATDeviceTypeChanged.Emit(event.EvtNATDeviceTypeChanged{ - TransportProtocol: transportProto, - NatDeviceType: network.NATDeviceTypeCone, - }) - return true, network.NATDeviceTypeCone - } - - // our current NAT Device Type is already CONE, nothing to do here. - return false, 0 - } - - // An observed address on an outbound connection that has ONLY been seen by one peer - if now.Sub(oa.lastSeen) <= oas.ttl && oa.numInbound == 0 && len(oa.seenBy) == 1 { - cnt++ - for s := range oa.seenBy { - seenBy[s] = struct{}{} - } - } - } - - // If four different peers observe a different address for us on each of four outbound connections, we - // are MOST probably behind a Symmetric NAT. - if cnt >= ActivationThresh && len(seenBy) >= ActivationThresh { - if currentNATType != network.NATDeviceTypeSymmetric { - oas.emitNATDeviceTypeChanged.Emit(event.EvtNATDeviceTypeChanged{ - TransportProtocol: transportProto, - NatDeviceType: network.NATDeviceTypeSymmetric, - }) - return true, network.NATDeviceTypeSymmetric - } - } - - return false, 0 -} - -func (oas *ObservedAddrManager) Close() error { - oas.closeOnce.Do(func() { - oas.ctxCancel() - - oas.mu.Lock() - oas.closed = true - oas.refreshTimer.Stop() - oas.mu.Unlock() - - oas.refCount.Wait() - oas.reachabilitySub.Close() - oas.host.Network().StopNotify((*obsAddrNotifiee)(oas)) - }) - return nil -} - -// observerGroup is a function that determines what part of -// a multiaddr counts as a different observer. for example, -// two ipfs nodes at the same IP/TCP transport would get -// the exact same NAT mapping; they would count as the -// same observer. This may protect against NATs who assign -// different ports to addresses at different IP hosts, but -// not TCP ports. -// -// Here, we use the root multiaddr address. This is mostly -// IP addresses. In practice, this is what we want. -func observerGroup(m ma.Multiaddr) string { - // TODO: If IPv6 rolls out we should mark /64 routing zones as one group - first, _ := ma.SplitFirst(m) - return string(first.Bytes()) -} - -// SetTTL sets the TTL of an observed address manager. -func (oas *ObservedAddrManager) SetTTL(ttl time.Duration) { - oas.mu.Lock() - defer oas.mu.Unlock() - if oas.closed { +func (o *ObservedAddrManager) maybeRecordObservation(conn connMultiaddrs, observed ma.Multiaddr) { + shouldRecord, localTW, observedTW := o.shouldRecordObservation(conn, observed) + if !shouldRecord { return } - oas.ttl = ttl - // refresh every ttl/2 so we don't forget observations from connected peers - oas.refreshTimer.Reset(ttl / 2) + log.Debugw("added own observed listen addr", "observed", observed) + + o.mu.Lock() + defer o.mu.Unlock() + o.recordObservationUnlocked(conn, localTW, observedTW) + select { + case o.addrRecordedNotif <- struct{}{}: + default: + } } -// TTL gets the TTL of an observed address manager. -func (oas *ObservedAddrManager) TTL() time.Duration { - oas.mu.RLock() - defer oas.mu.RUnlock() - return oas.ttl +func (o *ObservedAddrManager) recordObservationUnlocked(conn connMultiaddrs, localTW, observedTW thinWaist) { + if conn.IsClosed() { + // dont record if the connection is already closed. Any previous observations will be removed in + // the disconnected callback + return + } + localTWStr := string(localTW.TW.Bytes()) + observedTWStr := string(observedTW.TW.Bytes()) + observer, err := getObserver(conn.RemoteMultiaddr()) + if err != nil { + return + } + + prevObservedTWAddr, ok := o.connObservedTWAddrs[conn] + if !ok { + t, ok := o.localAddrs[string(localTW.Addr.Bytes())] + if !ok { + t = &thinWaistWithCount{ + thinWaist: localTW, + } + o.localAddrs[string(localTW.Addr.Bytes())] = t + } + t.Count++ + } else { + if prevObservedTWAddr.Equal(observedTW.TW) { + // we have received the same observation again, nothing to do + return + } + // if we have a previous entry remove it from externalAddrs + o.removeExternalAddrsUnlocked(observer, localTWStr, string(prevObservedTWAddr.Bytes())) + // no need to change the localAddrs map here + } + o.connObservedTWAddrs[conn] = observedTW.TW + o.addExternalAddrsUnlocked(observedTW.TW, observer, localTWStr, observedTWStr) } -type obsAddrNotifiee ObservedAddrManager - -func (on *obsAddrNotifiee) Listen(n network.Network, a ma.Multiaddr) {} -func (on *obsAddrNotifiee) ListenClose(n network.Network, a ma.Multiaddr) {} -func (on *obsAddrNotifiee) Connected(n network.Network, v network.Conn) {} -func (on *obsAddrNotifiee) Disconnected(n network.Network, v network.Conn) { - (*ObservedAddrManager)(on).removeConn(v) +func (o *ObservedAddrManager) removeExternalAddrsUnlocked(observer, localTWStr, observedTWStr string) { + s, ok := o.externalAddrs[localTWStr][observedTWStr] + if !ok { + return + } + s.ObservedBy[observer]-- + if s.ObservedBy[observer] <= 0 { + delete(s.ObservedBy, observer) + } + if len(s.ObservedBy) == 0 { + delete(o.externalAddrs[localTWStr], observedTWStr) + } + if len(o.externalAddrs[localTWStr]) == 0 { + delete(o.externalAddrs, localTWStr) + } +} + +func (o *ObservedAddrManager) addExternalAddrsUnlocked(observedTWAddr ma.Multiaddr, observer, localTWStr, observedTWStr string) { + s, ok := o.externalAddrs[localTWStr][observedTWStr] + if !ok { + s = &observerSet{ + ObservedTWAddr: observedTWAddr, + ObservedBy: make(map[string]int), + } + if _, ok := o.externalAddrs[localTWStr]; !ok { + o.externalAddrs[localTWStr] = make(map[string]*observerSet) + } + o.externalAddrs[localTWStr][observedTWStr] = s + } + s.ObservedBy[observer]++ +} + +func (o *ObservedAddrManager) removeConn(conn connMultiaddrs) { + if conn == nil { + return + } + o.mu.Lock() + defer o.mu.Unlock() + + // normalize before obtaining the thinWaist so that we are always dealing + // with the normalized form of the address + localTW, err := thinWaistForm(o.normalize(conn.LocalMultiaddr())) + if err != nil { + return + } + t, ok := o.localAddrs[string(localTW.Addr.Bytes())] + if !ok { + return + } + t.Count-- + if t.Count <= 0 { + delete(o.localAddrs, string(localTW.Addr.Bytes())) + } + + observedTWAddr, ok := o.connObservedTWAddrs[conn] + if !ok { + return + } + delete(o.connObservedTWAddrs, conn) + observer, err := getObserver(conn.RemoteMultiaddr()) + if err != nil { + return + } + + o.removeExternalAddrsUnlocked(observer, string(localTW.TW.Bytes()), string(observedTWAddr.Bytes())) + select { + case o.addrRecordedNotif <- struct{}{}: + default: + } +} + +func (o *ObservedAddrManager) getNATType() (tcpNATType, udpNATType network.NATDeviceType) { + o.mu.RLock() + defer o.mu.RUnlock() + + var tcpCounts, udpCounts []int + var tcpTotal, udpTotal int + for _, m := range o.externalAddrs { + isTCP := false + for _, v := range m { + if _, err := v.ObservedTWAddr.ValueForProtocol(ma.P_TCP); err == nil { + isTCP = true + } + break + } + for _, v := range m { + if isTCP { + tcpCounts = append(tcpCounts, len(v.ObservedBy)) + tcpTotal += len(v.ObservedBy) + } else { + udpCounts = append(udpCounts, len(v.ObservedBy)) + udpTotal += len(v.ObservedBy) + } + } + } + + sort.Sort(sort.Reverse(sort.IntSlice(tcpCounts))) + sort.Sort(sort.Reverse(sort.IntSlice(udpCounts))) + + tcpTopCounts, udpTopCounts := 0, 0 + for i := 0; i < maxExternalThinWaistAddrsPerLocalAddr && i < len(tcpCounts); i++ { + tcpTopCounts += tcpCounts[i] + } + for i := 0; i < maxExternalThinWaistAddrsPerLocalAddr && i < len(udpCounts); i++ { + udpTopCounts += udpCounts[i] + } + + // If the top elements cover more than 1/2 of all the observations, there's a > 50% chance that + // hole punching based on outputs of observed address manager will succeed + if tcpTotal >= 3*maxExternalThinWaistAddrsPerLocalAddr { + if tcpTopCounts >= tcpTotal/2 { + tcpNATType = network.NATDeviceTypeCone + } else { + tcpNATType = network.NATDeviceTypeSymmetric + } + } + if udpTotal >= 3*maxExternalThinWaistAddrsPerLocalAddr { + if udpTopCounts >= udpTotal/2 { + udpNATType = network.NATDeviceTypeCone + } else { + udpNATType = network.NATDeviceTypeSymmetric + } + } + return +} + +func (o *ObservedAddrManager) Close() error { + o.ctxCancel() + o.wg.Wait() + return nil } diff --git a/go-libp2p/p2p/protocol/identify/obsaddr_glass_test.go b/go-libp2p/p2p/protocol/identify/obsaddr_glass_test.go index f96d3a3..31fd4f5 100644 --- a/go-libp2p/p2p/protocol/identify/obsaddr_glass_test.go +++ b/go-libp2p/p2p/protocol/identify/obsaddr_glass_test.go @@ -5,77 +5,16 @@ package identify import ( "fmt" + "sync/atomic" "testing" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" ) -func TestObservedAddrGroupKey(t *testing.T) { - oa1 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/tcp/2345")} - oa2 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/tcp/1231")} - oa3 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.5/tcp/1231")} - oa4 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1231")} - oa5 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1531")} - oa6 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1531/quic")} - oa7 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.4/udp/1111/quic")} - oa8 := &observedAddr{addr: ma.StringCast("/ip4/1.2.3.5/udp/1111/quic")} - - // different ports, same IP => same key - require.Equal(t, oa1.groupKey(), oa2.groupKey()) - // different IPs => different key - require.NotEqual(t, oa2.groupKey(), oa3.groupKey()) - // same port, different protos => different keys - require.NotEqual(t, oa3.groupKey(), oa4.groupKey()) - // same port, same address, different protos => different keys - require.NotEqual(t, oa2.groupKey(), oa4.groupKey()) - // udp works as well - require.Equal(t, oa4.groupKey(), oa5.groupKey()) - // udp and quic are different - require.NotEqual(t, oa5.groupKey(), oa6.groupKey()) - // quic works as well - require.Equal(t, oa6.groupKey(), oa7.groupKey()) - require.NotEqual(t, oa7.groupKey(), oa8.groupKey()) -} - -type mockHost struct { - addrs []ma.Multiaddr - listenAddrs []ma.Multiaddr - ifaceListenAddrs []ma.Multiaddr -} - -// InterfaceListenAddresses implements listenAddrsProvider -func (h *mockHost) InterfaceListenAddresses() ([]ma.Multiaddr, error) { - return h.ifaceListenAddrs, nil -} - -// ListenAddresses implements listenAddrsProvider -func (h *mockHost) ListenAddresses() []ma.Multiaddr { - return h.listenAddrs -} - -// Addrs implements addrsProvider -func (h *mockHost) Addrs() []ma.Multiaddr { - return h.addrs -} - -// NormalizeMultiaddr implements normalizeMultiaddrer -func (h *mockHost) NormalizeMultiaddr(m ma.Multiaddr) ma.Multiaddr { - original := m - for { - rest, tail := ma.SplitLast(m) - if rest == nil { - return original - } - if tail.Protocol().Code == ma.P_WEBTRANSPORT { - return m - } - m = rest - } -} - type mockConn struct { local, remote ma.Multiaddr + isClosed atomic.Bool } // LocalMultiaddr implements connMultiaddrProvider @@ -88,21 +27,30 @@ func (c *mockConn) RemoteMultiaddr() ma.Multiaddr { return c.remote } +func (c *mockConn) Close() { + c.isClosed.Store(true) +} + +func (c *mockConn) IsClosed() bool { + return c.isClosed.Load() +} + func TestShouldRecordObservationWithWebTransport(t *testing.T) { listenAddr := ma.StringCast("/ip4/0.0.0.0/udp/0/quic-v1/webtransport/certhash/uEgNmb28") ifaceAddr := ma.StringCast("/ip4/10.0.0.2/udp/9999/quic-v1/webtransport/certhash/uEgNmb28") - h := &mockHost{ - listenAddrs: []ma.Multiaddr{listenAddr}, - ifaceListenAddrs: []ma.Multiaddr{ifaceAddr}, - addrs: []ma.Multiaddr{listenAddr}, - } + listenAddrs := func() []ma.Multiaddr { return []ma.Multiaddr{listenAddr} } + ifaceListenAddrs := func() ([]ma.Multiaddr, error) { return []ma.Multiaddr{ifaceAddr}, nil } + addrs := func() []ma.Multiaddr { return []ma.Multiaddr{listenAddr} } + c := &mockConn{ local: listenAddr, remote: ma.StringCast("/ip4/1.2.3.6/udp/1236/quic-v1/webtransport"), } observedAddr := ma.StringCast("/ip4/1.2.3.4/udp/1231/quic-v1/webtransport") - - require.True(t, shouldRecordObservation(h, h, c, observedAddr)) + o, err := NewObservedAddrManager(listenAddrs, addrs, ifaceListenAddrs, normalize) + require.NoError(t, err) + shouldRecord, _, _ := o.shouldRecordObservation(c, observedAddr) + require.True(t, shouldRecord) } func TestShouldRecordObservationWithNAT64Addr(t *testing.T) { @@ -111,11 +59,11 @@ func TestShouldRecordObservationWithNAT64Addr(t *testing.T) { listenAddr2 := ma.StringCast("/ip6/::/tcp/1234") ifaceAddr2 := ma.StringCast("/ip6/1::1/tcp/4321") - h := &mockHost{ - listenAddrs: []ma.Multiaddr{listenAddr1, listenAddr2}, - ifaceListenAddrs: []ma.Multiaddr{ifaceAddr1, ifaceAddr2}, - addrs: []ma.Multiaddr{listenAddr1, listenAddr2}, - } + var ( + listenAddrs = func() []ma.Multiaddr { return []ma.Multiaddr{listenAddr1, listenAddr2} } + ifaceListenAddrs = func() ([]ma.Multiaddr, error) { return []ma.Multiaddr{ifaceAddr1, ifaceAddr2}, nil } + addrs = func() []ma.Multiaddr { return []ma.Multiaddr{listenAddr1, listenAddr2} } + ) c := &mockConn{ local: listenAddr1, remote: ma.StringCast("/ip4/1.2.3.6/tcp/4321"), @@ -142,12 +90,70 @@ func TestShouldRecordObservationWithNAT64Addr(t *testing.T) { failureReason: "NAT64 IPv6 address shouldn't be observed", }, } + + o, err := NewObservedAddrManager(listenAddrs, addrs, ifaceListenAddrs, normalize) + require.NoError(t, err) for i, tc := range cases { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - if shouldRecordObservation(h, h, c, tc.addr) != tc.want { + if shouldRecord, _, _ := o.shouldRecordObservation(c, tc.addr); shouldRecord != tc.want { t.Fatalf("%s %s", tc.addr, tc.failureReason) } }) } } + +func TestThinWaistForm(t *testing.T) { + tc := []struct { + input string + tw string + rest string + err bool + }{{ + input: "/ip4/1.2.3.4/tcp/1", + tw: "/ip4/1.2.3.4/tcp/1", + rest: "", + }, { + input: "/ip4/1.2.3.4/tcp/1/ws", + tw: "/ip4/1.2.3.4/tcp/1", + rest: "/ws", + }, { + input: "/ip4/127.0.0.1/udp/1/quic-v1", + tw: "/ip4/127.0.0.1/udp/1", + rest: "/quic-v1", + }, { + input: "/ip4/1.2.3.4/udp/1/quic-v1/webtransport", + tw: "/ip4/1.2.3.4/udp/1", + rest: "/quic-v1/webtransport", + }, { + input: "/ip4/1.2.3.4/", + err: true, + }, { + input: "/tcp/1", + err: true, + }, { + input: "/ip6/::1/tcp/1", + tw: "/ip6/::1/tcp/1", + rest: "", + }} + for i, tt := range tc { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + inputAddr := ma.StringCast(tt.input) + tw, err := thinWaistForm(inputAddr) + if tt.err { + require.Equal(t, tw, thinWaist{}) + require.Error(t, err) + return + } + wantTW := ma.StringCast(tt.tw) + var restTW ma.Multiaddr + if tt.rest != "" { + restTW = ma.StringCast(tt.rest) + } + require.Equal(t, tw.Addr, inputAddr, "%s %s", tw.Addr, inputAddr) + require.Equal(t, wantTW, tw.TW, "%s %s", tw.TW, wantTW) + require.Equal(t, restTW, tw.Rest, "%s %s", restTW, tw.Rest) + }) + } + +} diff --git a/go-libp2p/p2p/protocol/identify/obsaddr_test.go b/go-libp2p/p2p/protocol/identify/obsaddr_test.go index 2987b01..9c2d8de 100644 --- a/go-libp2p/p2p/protocol/identify/obsaddr_test.go +++ b/go-libp2p/p2p/protocol/identify/obsaddr_test.go @@ -1,436 +1,662 @@ -package identify_test +package identify import ( - "crypto/rand" + crand "crypto/rand" + "fmt" + "net" "testing" "time" - ic "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/event" - "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" + blankhost "github.com/libp2p/go-libp2p/p2p/host/blank" "github.com/libp2p/go-libp2p/p2p/host/eventbus" - mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" - "github.com/libp2p/go-libp2p/p2p/protocol/identify" + swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" ) -type harness struct { - t *testing.T - - mocknet mocknet.Mocknet - host host.Host - - oas *identify.ObservedAddrManager +func newConn(local, remote ma.Multiaddr) *mockConn { + return &mockConn{local: local, remote: remote} } -func (h *harness) add(observer ma.Multiaddr) peer.ID { - // create a new fake peer. - sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader) - if err != nil { - h.t.Fatal(err) - } - h2, err := h.mocknet.AddPeer(sk, observer) - if err != nil { - h.t.Fatal(err) - } - _, err = h.mocknet.LinkPeers(h.host.ID(), h2.ID()) - if err != nil { - h.t.Fatal(err) - } - return h2.ID() -} - -func (h *harness) conn(observer peer.ID) network.Conn { - c, err := h.mocknet.ConnectPeers(h.host.ID(), observer) - if err != nil { - h.t.Fatal(err) - } - if c.Stat().Direction != network.DirOutbound { - h.t.Fatal("expected conn direction to be outbound") - } - return c -} - -func (h *harness) connInbound(observer peer.ID) network.Conn { - c, err := h.mocknet.ConnectPeers(observer, h.host.ID()) - if err != nil { - h.t.Fatal(err) - } - - c = mocknet.ConnComplement(c) - if c.Stat().Direction != network.DirInbound { - h.t.Fatal("expected conn direction to be inbound") - } - return c -} - -func (h *harness) observe(observed ma.Multiaddr, observer peer.ID) network.Conn { - c := h.conn(observer) - h.oas.Record(c, observed) - time.Sleep(200 * time.Millisecond) // let the worker run - return c -} - -func (h *harness) observeInbound(observed ma.Multiaddr, observer peer.ID) network.Conn { - c := h.connInbound(observer) - h.oas.Record(c, observed) - time.Sleep(200 * time.Millisecond) // let the worker run - return c -} - -func newHarness(t *testing.T) harness { - return newHarnessWithMa(t, ma.StringCast("/ip4/127.0.0.1/tcp/10086")) -} - -func newHarnessWithMa(t *testing.T, listenAddr ma.Multiaddr) harness { - mn := mocknet.New() - sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader) - require.NoError(t, err) - h, err := mn.AddPeer(sk, listenAddr) - require.NoError(t, err) - oas, err := identify.NewObservedAddrManager(h) - require.NoError(t, err) - t.Cleanup(func() { - mn.Close() - oas.Close() - }) - return harness{ - oas: oas, - mocknet: mn, - host: h, - t: t, - } -} - -// TestObsAddrSet -func TestObsAddrSet(t *testing.T) { - addrsMatch := func(a, b []ma.Multiaddr) bool { - if len(a) != len(b) { - return false +func normalize(addr ma.Multiaddr) ma.Multiaddr { + for { + out, last := ma.SplitLast(addr) + if last == nil { + return addr } - for _, aa := range a { - if !ma.Contains(b, aa) { - return false + if _, err := last.ValueForProtocol(ma.P_CERTHASH); err != nil { + return addr + } + addr = out + } +} + +func addrsEqual(a, b []ma.Multiaddr) bool { + if len(b) != len(a) { + return false + } + for _, x := range b { + found := false + for _, y := range a { + if y.Equal(x) { + found = true + break } } - return true - } - - a1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - a2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232") - a3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233") - a4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234") - a5 := ma.StringCast("/ip4/1.2.3.4/tcp/1235") - - b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236") - b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237") - b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237") - b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237") - b5 := ma.StringCast("/ip4/1.2.3.10/tcp/1237") - - harness := newHarness(t) - if !addrsMatch(harness.oas.Addrs(), nil) { - t.Error("addrs should be empty") - } - - pa4 := harness.add(a4) - pa5 := harness.add(a5) - - pb1 := harness.add(b1) - pb2 := harness.add(b2) - pb3 := harness.add(b3) - pb4 := harness.add(b4) - pb5 := harness.add(b5) - - harness.observe(a1, pa4) - harness.observe(a2, pa4) - harness.observe(a3, pa4) - - // these are all different so we should not yet get them. - if !addrsMatch(harness.oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (once)") - } - - // same observer, so should not yet get them. - harness.observe(a1, pa4) - harness.observe(a2, pa4) - harness.observe(a3, pa4) - if !addrsMatch(harness.oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (same obs)") - } - - // different observer, but same observer group. - harness.observe(a1, pa5) - harness.observe(a2, pa5) - harness.observe(a3, pa5) - if !addrsMatch(harness.oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (same obs group)") - } - - harness.observe(a1, pb1) - harness.observe(a1, pb2) - harness.observe(a1, pb3) - if !addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1}) { - t.Error("addrs should only have a1") - } - - harness.observe(a2, pa5) - harness.observe(a1, pa5) - harness.observe(a1, pa5) - harness.observe(a2, pb1) - harness.observe(a1, pb1) - harness.observe(a1, pb1) - harness.observe(a2, pb2) - harness.observe(a1, pb2) - harness.observe(a1, pb2) - harness.observe(a2, pb4) - harness.observe(a2, pb5) - if !addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1, a2}) { - t.Error("addrs should only have a1, a2") - } - - // force a refresh. - harness.oas.SetTTL(time.Millisecond * 200) - require.Eventuallyf(t, - func() bool { return addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1, a2}) }, - time.Second, - 50*time.Millisecond, - "addrs should only have %s, %s; have %s", a1, a2, harness.oas.Addrs(), - ) - - // disconnect from all but b5. - for _, p := range harness.host.Network().Peers() { - if p == pb5 { - continue + if !found { + return false } - harness.host.Network().ClosePeer(p) } - - // Wait for all other addresses to time out. - // After that, we hould still have a2. - require.Eventuallyf(t, - func() bool { return addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a2}) }, - time.Second, - 50*time.Millisecond, - "should only have a2 (%s), have: %v", a2, harness.oas.Addrs(), - ) - harness.host.Network().ClosePeer(pb5) - - // wait for all addresses to timeout - require.Eventually(t, - func() bool { return len(harness.oas.Addrs()) == 0 }, - 400*time.Millisecond, - 20*time.Millisecond, - "addrs should have timed out", - ) + for _, x := range a { + found := false + for _, y := range b { + if y.Equal(x) { + found = true + break + } + } + if !found { + return false + } + } + return true } -func TestObservedAddrFiltering(t *testing.T) { - harness := newHarness(t) - require.Empty(t, harness.oas.Addrs()) - - // IP4/TCP - it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232") - it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233") - it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234") - it5 := ma.StringCast("/ip4/1.2.3.4/tcp/1235") - it6 := ma.StringCast("/ip4/1.2.3.4/tcp/1236") - it7 := ma.StringCast("/ip4/1.2.3.4/tcp/1237") - - // observers - b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236") - b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237") - b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237") - b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237") - b5 := ma.StringCast("/ip4/1.2.3.10/tcp/1237") - - b6 := ma.StringCast("/ip4/1.2.3.11/tcp/1237") - b7 := ma.StringCast("/ip4/1.2.3.12/tcp/1237") - - // These are all observers in the same group. - b8 := ma.StringCast("/ip4/1.2.3.13/tcp/1237") - b9 := ma.StringCast("/ip4/1.2.3.13/tcp/1238") - b10 := ma.StringCast("/ip4/1.2.3.13/tcp/1239") - - peers := []peer.ID{ - harness.add(b1), - harness.add(b2), - harness.add(b3), - harness.add(b4), - harness.add(b5), - - harness.add(b6), - harness.add(b7), - - harness.add(b8), - harness.add(b9), - harness.add(b10), - } - for i := 0; i < 4; i++ { - harness.observe(it1, peers[i]) - harness.observe(it2, peers[i]) - harness.observe(it3, peers[i]) - harness.observe(it4, peers[i]) - harness.observe(it5, peers[i]) - harness.observe(it6, peers[i]) - harness.observe(it7, peers[i]) +func TestObservedAddrManager(t *testing.T) { + tcp4ListenAddr := ma.StringCast("/ip4/192.168.1.100/tcp/1") + quic4ListenAddr := ma.StringCast("/ip4/0.0.0.0/udp/1/quic-v1") + webTransport4ListenAddr := ma.StringCast("/ip4/0.0.0.0/udp/1/quic-v1/webtransport/certhash/uEgNmb28") + tcp6ListenAddr := ma.StringCast("/ip6/2004::1/tcp/1") + quic6ListenAddr := ma.StringCast("/ip6/::/udp/1/quic-v1") + webTransport6ListenAddr := ma.StringCast("/ip6/::/udp/1/quic-v1/webtransport/certhash/uEgNmb28") + newObservedAddrMgr := func() *ObservedAddrManager { + listenAddrs := []ma.Multiaddr{ + tcp4ListenAddr, quic4ListenAddr, webTransport4ListenAddr, tcp6ListenAddr, quic6ListenAddr, webTransport6ListenAddr, + } + listenAddrsFunc := func() []ma.Multiaddr { + return listenAddrs + } + interfaceListenAddrsFunc := func() ([]ma.Multiaddr, error) { + return listenAddrs, nil + } + o, err := NewObservedAddrManager(listenAddrsFunc, listenAddrsFunc, + interfaceListenAddrsFunc, normalize) + if err != nil { + t.Fatal(err) + } + return o } - harness.observe(it1, peers[4]) - harness.observe(it7, peers[4]) + checkAllEntriesRemoved := func(o *ObservedAddrManager) bool { + return len(o.Addrs()) == 0 && len(o.externalAddrs) == 0 && len(o.connObservedTWAddrs) == 0 && len(o.localAddrs) == 0 + } + t.Run("Single Observation", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + observed := ma.StringCast("/ip4/2.2.2.2/tcp/2") + c1 := newConn(tcp4ListenAddr, ma.StringCast("/ip4/1.2.3.1/tcp/1")) + c2 := newConn(tcp4ListenAddr, ma.StringCast("/ip4/1.2.3.2/tcp/1")) + c3 := newConn(tcp4ListenAddr, ma.StringCast("/ip4/1.2.3.3/tcp/1")) + c4 := newConn(tcp4ListenAddr, ma.StringCast("/ip4/1.2.3.4/tcp/1")) + o.Record(c1, observed) + o.Record(c2, observed) + o.Record(c3, observed) + o.Record(c4, observed) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observed}) + }, 1*time.Second, 100*time.Millisecond) + o.removeConn(c1) + o.removeConn(c2) + o.removeConn(c3) + o.removeConn(c4) + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) - addrs := harness.oas.Addrs() - require.Len(t, addrs, 2) - require.Contains(t, addrs, it1) - require.Contains(t, addrs, it7) + t.Run("WebTransport inferred from QUIC", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + observedQuic := ma.StringCast("/ip4/2.2.2.2/udp/2/quic-v1") + observedWebTransport := ma.StringCast("/ip4/2.2.2.2/udp/2/quic-v1/webtransport") + c1 := newConn(quic4ListenAddr, ma.StringCast("/ip4/1.2.3.1/udp/1/quic-v1")) + c2 := newConn(quic4ListenAddr, ma.StringCast("/ip4/1.2.3.2/udp/1/quic-v1")) + c3 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.3/udp/1/quic-v1/webtransport")) + c4 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport")) + o.Record(c1, observedQuic) + o.Record(c2, observedQuic) + o.Record(c3, observedWebTransport) + o.Record(c4, observedWebTransport) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic, observedWebTransport}) + }, 1*time.Second, 100*time.Millisecond) + o.removeConn(c1) + o.removeConn(c2) + o.removeConn(c3) + o.removeConn(c4) + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) - // Bump the number of observations so 1 & 7 have 7 observations. - harness.observe(it1, peers[5]) - harness.observe(it1, peers[6]) - harness.observe(it7, peers[5]) - harness.observe(it7, peers[6]) + t.Run("SameObservers", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() - // Add an observation from IP 1.2.3.13 - // 2 & 3 now have 5 observations - harness.observe(it2, peers[7]) - harness.observe(it3, peers[7]) + observedQuic := ma.StringCast("/ip4/2.2.2.2/udp/2/quic-v1") - addrs = harness.oas.Addrs() - require.Len(t, addrs, 2) - require.Contains(t, addrs, it1) - require.Contains(t, addrs, it7) + const N = 4 // ActivationThresh + var ob1, ob2 [N]connMultiaddrs + for i := 0; i < N; i++ { + ob1[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + ob2[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + } + for i := 0; i < N-1; i++ { + o.Record(ob1[i], observedQuic) + o.Record(ob2[i], observedQuic) + } + time.Sleep(100 * time.Millisecond) + require.Equal(t, o.Addrs(), []ma.Multiaddr{}) - // Add an inbound observation from IP 1.2.3.13, it should override the - // existing observation and it should make these addresses win even - // though we have fewer observations. - // - // 2 & 3 now have 6 observations. - harness.observeInbound(it2, peers[8]) - harness.observeInbound(it3, peers[8]) - addrs = harness.oas.Addrs() - require.Len(t, addrs, 2) - require.Contains(t, addrs, it2) - require.Contains(t, addrs, it3) + // We should have a valid address now + o.Record(ob1[N-1], observedQuic) + o.Record(ob2[N-1], observedQuic) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic}) + }, 2*time.Second, 100*time.Millisecond) - // Adding an outbound observation shouldn't "downgrade" it. - // - // 2 & 3 now have 7 observations. - harness.observe(it2, peers[9]) - harness.observe(it3, peers[9]) - addrs = harness.oas.Addrs() - require.Len(t, addrs, 2) - require.Contains(t, addrs, it2) - require.Contains(t, addrs, it3) + // Now disconnect first observer group + for i := 0; i < N; i++ { + o.removeConn(ob1[i]) + } + time.Sleep(100 * time.Millisecond) + if !addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic}) { + t.Fatalf("address removed too earyly %v %v", o.Addrs(), observedQuic) + } + + // Now disconnect the second group to check cleanup + for i := 0; i < N; i++ { + o.removeConn(ob2[i]) + } + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 2*time.Second, 100*time.Millisecond) + }) + t.Run("SameObserversDifferentAddrs", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + + observedQuic1 := ma.StringCast("/ip4/2.2.2.2/udp/2/quic-v1") + observedQuic2 := ma.StringCast("/ip4/2.2.2.2/udp/3/quic-v1") + + const N = 4 // ActivationThresh + var ob1, ob2 [N]connMultiaddrs + for i := 0; i < N; i++ { + ob1[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + ob2[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + } + for i := 0; i < N-1; i++ { + o.Record(ob1[i], observedQuic1) + o.Record(ob2[i], observedQuic2) + } + time.Sleep(100 * time.Millisecond) + require.Equal(t, o.Addrs(), []ma.Multiaddr{}) + + // We should have a valid address now + o.Record(ob1[N-1], observedQuic1) + o.Record(ob2[N-1], observedQuic2) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic1, observedQuic2}) + }, 2*time.Second, 100*time.Millisecond) + + // Now disconnect first observer group + for i := 0; i < N; i++ { + o.removeConn(ob1[i]) + } + time.Sleep(100 * time.Millisecond) + if !addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic2}) { + t.Fatalf("address removed too earyly %v %v", o.Addrs(), observedQuic2) + } + + // Now disconnect the second group to check cleanup + for i := 0; i < N; i++ { + o.removeConn(ob2[i]) + } + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 2*time.Second, 100*time.Millisecond) + }) + + t.Run("Old observations discarded", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + c1 := newConn(quic4ListenAddr, ma.StringCast("/ip4/1.2.3.1/udp/1/quic-v1")) + c2 := newConn(quic4ListenAddr, ma.StringCast("/ip4/1.2.3.2/udp/1/quic-v1")) + c3 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.3/udp/1/quic-v1/webtransport")) + c4 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport")) + var observedQuic, observedWebTransport ma.Multiaddr + for i := 0; i < 10; i++ { + // Change the IP address in each observation + observedQuic = ma.StringCast(fmt.Sprintf("/ip4/2.2.2.%d/udp/2/quic-v1", i)) + observedWebTransport = ma.StringCast(fmt.Sprintf("/ip4/2.2.2.%d/udp/2/quic-v1/webtransport", i)) + o.Record(c1, observedQuic) + o.Record(c2, observedQuic) + o.Record(c3, observedWebTransport) + o.Record(c4, observedWebTransport) + time.Sleep(20 * time.Millisecond) + } + + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedQuic, observedWebTransport}) + }, 1*time.Second, 100*time.Millisecond) + + tw, err := thinWaistForm(quic4ListenAddr) + require.NoError(t, err) + require.Less(t, len(o.externalAddrs[string(tw.TW.Bytes())]), 2) + + require.Equal(t, o.AddrsFor(webTransport4ListenAddr), []ma.Multiaddr{observedWebTransport}) + require.Equal(t, o.AddrsFor(quic4ListenAddr), []ma.Multiaddr{observedQuic}) + + o.removeConn(c1) + o.removeConn(c2) + o.removeConn(c3) + o.removeConn(c4) + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) + + t.Run("Many connection many observations", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + const N = 100 + var tcpConns, quicConns, webTransportConns [N]*mockConn + for i := 0; i < N; i++ { + tcpConns[i] = newConn(tcp4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/tcp/1", i))) + quicConns[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + webTransportConns[i] = newConn(webTransport4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1/webtransport", i))) + } + var observedQuic, observedWebTransport, observedTCP ma.Multiaddr + for i := 0; i < N; i++ { + for j := 0; j < 5; j++ { + // ip addr has the form 2.2.. + observedQuic = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/udp/2/quic-v1", i/10, j)) + observedWebTransport = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/udp/2/quic-v1/webtransport", i/10, j)) + observedTCP = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/tcp/2", i/10, j)) + o.Record(tcpConns[i], observedTCP) + o.Record(quicConns[i], observedQuic) + o.Record(webTransportConns[i], observedWebTransport) + time.Sleep(10 * time.Millisecond) + } + } + // At this point we have 10 groups of N / 10 with 10 observations for every connection + // The output should remain stable + require.Eventually(t, func() bool { + return len(o.Addrs()) == 3*maxExternalThinWaistAddrsPerLocalAddr + }, 1*time.Second, 100*time.Millisecond) + addrs := o.Addrs() + for i := 0; i < 10; i++ { + require.ElementsMatch(t, o.Addrs(), addrs, "%s %s", o.Addrs(), addrs) + time.Sleep(10 * time.Millisecond) + } + + // Now we bias a few address counts and check for sorting correctness + var resTCPAddrs, resQuicAddrs, resWebTransportAddrs [maxExternalThinWaistAddrsPerLocalAddr]ma.Multiaddr + for i := 0; i < maxExternalThinWaistAddrsPerLocalAddr; i++ { + resTCPAddrs[i] = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/tcp/2", 9-i)) + resQuicAddrs[i] = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/udp/2/quic-v1", 9-i)) + resWebTransportAddrs[i] = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/udp/2/quic-v1/webtransport", 9-i)) + o.Record(tcpConns[i], resTCPAddrs[i]) + o.Record(quicConns[i], resQuicAddrs[i]) + o.Record(webTransportConns[i], resWebTransportAddrs[i]) + time.Sleep(10 * time.Millisecond) + } + var allAddrs []ma.Multiaddr + allAddrs = append(allAddrs, resTCPAddrs[:]...) + allAddrs = append(allAddrs, resQuicAddrs[:]...) + allAddrs = append(allAddrs, resWebTransportAddrs[:]...) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), allAddrs) + }, 1*time.Second, 100*time.Millisecond) + + for i := 0; i < N; i++ { + o.removeConn(tcpConns[i]) + o.removeConn(quicConns[i]) + o.removeConn(webTransportConns[i]) + } + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) + + t.Run("WebTransport certhash", func(t *testing.T) { + o := newObservedAddrMgr() + observedWebTransport := ma.StringCast("/ip4/2.2.2.2/udp/1/quic-v1/webtransport") + c1 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.1/udp/1/quic-v1/webtransport")) + c2 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.2/udp/1/quic-v1/webtransport")) + c3 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.3/udp/1/quic-v1/webtransport")) + c4 := newConn(webTransport4ListenAddr, ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport")) + o.Record(c1, observedWebTransport) + o.Record(c2, observedWebTransport) + o.Record(c3, observedWebTransport) + o.Record(c4, observedWebTransport) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedWebTransport}) + }, 1*time.Second, 100*time.Millisecond) + o.removeConn(c1) + o.removeConn(c2) + o.removeConn(c3) + o.removeConn(c4) + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) + + t.Run("getNATType", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + + observedWebTransport := ma.StringCast("/ip4/2.2.2.2/udp/1/quic-v1/webtransport") + var udpConns [5 * maxExternalThinWaistAddrsPerLocalAddr]connMultiaddrs + for i := 0; i < len(udpConns); i++ { + udpConns[i] = newConn(webTransport4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1/webtransport", i))) + o.Record(udpConns[i], observedWebTransport) + time.Sleep(10 * time.Millisecond) + } + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedWebTransport}) + }, 1*time.Second, 100*time.Millisecond) + + tcpNAT, udpNAT := o.getNATType() + require.Equal(t, tcpNAT, network.NATDeviceTypeUnknown) + require.Equal(t, udpNAT, network.NATDeviceTypeCone) + }) + t.Run("NATTypeSymmetric", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + const N = 100 + var tcpConns, quicConns [N]*mockConn + for i := 0; i < N; i++ { + tcpConns[i] = newConn(tcp4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/tcp/1", i))) + quicConns[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + } + var observedQuic, observedTCP ma.Multiaddr + for i := 0; i < N; i++ { + // ip addr has the form 2.2..2 + observedQuic = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.2/udp/2/quic-v1", i%20)) + observedTCP = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.2/tcp/2", i%20)) + o.Record(tcpConns[i], observedTCP) + o.Record(quicConns[i], observedQuic) + time.Sleep(10 * time.Millisecond) + } + // At this point we have 20 groups with 5 observations for every connection + // The output should remain stable + require.Eventually(t, func() bool { + return len(o.Addrs()) == 2*maxExternalThinWaistAddrsPerLocalAddr + }, 1*time.Second, 100*time.Millisecond) + + tcpNAT, udpNAT := o.getNATType() + require.Equal(t, tcpNAT, network.NATDeviceTypeSymmetric) + require.Equal(t, udpNAT, network.NATDeviceTypeSymmetric) + + for i := 0; i < N; i++ { + o.removeConn(tcpConns[i]) + o.removeConn(quicConns[i]) + } + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) + t.Run("Nill Input", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + o.maybeRecordObservation(nil, nil) + remoteAddr := ma.StringCast("/ip4/1.2.3.4/tcp/1") + o.maybeRecordObservation(newConn(tcp4ListenAddr, remoteAddr), nil) + o.maybeRecordObservation(nil, remoteAddr) + o.AddrsFor(nil) + o.removeConn(nil) + }) + + t.Run("Nat Emitter", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + bus := eventbus.NewBus() + + s := swarmt.GenSwarm(t, swarmt.EventBus(bus)) + h := blankhost.NewBlankHost(s, blankhost.WithEventBus(bus)) + defer h.Close() + // make reachability private + emitter, err := bus.Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful) + require.NoError(t, err) + emitter.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate}) + + // start nat emitter + n, err := newNATEmitter(h, o, 10*time.Millisecond) + require.NoError(t, err) + defer n.Close() + + sub, err := bus.Subscribe(new(event.EvtNATDeviceTypeChanged)) + require.NoError(t, err) + observedWebTransport := ma.StringCast("/ip4/2.2.2.2/udp/1/quic-v1/webtransport") + var udpConns [5 * maxExternalThinWaistAddrsPerLocalAddr]connMultiaddrs + for i := 0; i < len(udpConns); i++ { + udpConns[i] = newConn(webTransport4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1/webtransport", i))) + o.Record(udpConns[i], observedWebTransport) + time.Sleep(10 * time.Millisecond) + } + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), []ma.Multiaddr{observedWebTransport}) + }, 1*time.Second, 100*time.Millisecond) + + var e interface{} + select { + case e = <-sub.Out(): + case <-time.After(2 * time.Second): + t.Fatalf("expected NAT change event") + } + evt := e.(event.EvtNATDeviceTypeChanged) + require.Equal(t, evt.TransportProtocol, network.NATTransportUDP) + require.Equal(t, evt.NatDeviceType, network.NATDeviceTypeCone) + }) + t.Run("Many connection many observations IP4 And IP6", func(t *testing.T) { + o := newObservedAddrMgr() + defer o.Close() + const N = 100 + var tcp4Conns, quic4Conns, webTransport4Conns [N]*mockConn + var tcp6Conns, quic6Conns, webTransport6Conns [N]*mockConn + for i := 0; i < N; i++ { + tcp4Conns[i] = newConn(tcp4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/tcp/1", i))) + quic4Conns[i] = newConn(quic4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1", i))) + webTransport4Conns[i] = newConn(webTransport4ListenAddr, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.%d/udp/1/quic-v1/webtransport", i))) + + tcp6Conns[i] = newConn(tcp6ListenAddr, ma.StringCast(fmt.Sprintf("/ip6/20%02x::/tcp/1", i))) + quic6Conns[i] = newConn(quic6ListenAddr, ma.StringCast(fmt.Sprintf("/ip6/20%02x::/udp/1/quic-v1", i))) + webTransport6Conns[i] = newConn(webTransport6ListenAddr, ma.StringCast(fmt.Sprintf("/ip6/20%02x::/udp/1/quic-v1/webtransport", i))) + } + var observedQUIC4, observedWebTransport4, observedTCP4 ma.Multiaddr + var observedQUIC6, observedWebTransport6, observedTCP6 ma.Multiaddr + for i := 0; i < N; i++ { + for j := 0; j < 5; j++ { + // ip addr has the form 2.2.. + observedQUIC4 = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/udp/2/quic-v1", i/10, j)) + observedWebTransport4 = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/udp/2/quic-v1/webtransport", i/10, j)) + observedTCP4 = ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.%d/tcp/2", i/10, j)) + + // ip addr has the form 20XX::YY + observedQUIC6 = ma.StringCast(fmt.Sprintf("/ip6/20%02x::%02x/udp/2/quic-v1", i/10, j)) + observedWebTransport6 = ma.StringCast(fmt.Sprintf("/ip6/20%02x::%02x/udp/2/quic-v1/webtransport", i/10, j)) + observedTCP6 = ma.StringCast(fmt.Sprintf("/ip6/20%02x::%02x/tcp/2", i/10, j)) + + o.maybeRecordObservation(tcp4Conns[i], observedTCP4) + o.maybeRecordObservation(quic4Conns[i], observedQUIC4) + o.maybeRecordObservation(webTransport4Conns[i], observedWebTransport4) + + o.maybeRecordObservation(tcp6Conns[i], observedTCP6) + o.maybeRecordObservation(quic6Conns[i], observedQUIC6) + o.maybeRecordObservation(webTransport6Conns[i], observedWebTransport6) + } + } + // At this point we have 10 groups of N / 10 with 10 observations for every connection + // The output should remain stable + require.Eventually(t, func() bool { + return len(o.Addrs()) == 2*3*maxExternalThinWaistAddrsPerLocalAddr + }, 1*time.Second, 100*time.Millisecond) + addrs := o.Addrs() + for i := 0; i < 10; i++ { + require.ElementsMatch(t, o.Addrs(), addrs, "%s %s", o.Addrs(), addrs) + time.Sleep(10 * time.Millisecond) + } + + // Now we bias a few address counts and check for sorting correctness + var resTCPAddrs, resQuicAddrs, resWebTransportAddrs []ma.Multiaddr + + for i, idx := 0, 0; i < maxExternalThinWaistAddrsPerLocalAddr; i++ { + resTCPAddrs = append(resTCPAddrs, ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/tcp/2", 9-i))) + resQuicAddrs = append(resQuicAddrs, ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/udp/2/quic-v1", 9-i))) + resWebTransportAddrs = append(resWebTransportAddrs, ma.StringCast(fmt.Sprintf("/ip4/2.2.%d.4/udp/2/quic-v1/webtransport", 9-i))) + + o.maybeRecordObservation(tcp4Conns[i], resTCPAddrs[idx]) + o.maybeRecordObservation(quic4Conns[i], resQuicAddrs[idx]) + o.maybeRecordObservation(webTransport4Conns[i], resWebTransportAddrs[idx]) + idx++ + + resTCPAddrs = append(resTCPAddrs, ma.StringCast(fmt.Sprintf("/ip6/20%02x::04/tcp/2", 9-i))) + resQuicAddrs = append(resQuicAddrs, ma.StringCast(fmt.Sprintf("/ip6/20%02x::04/udp/2/quic-v1", 9-i))) + resWebTransportAddrs = append(resWebTransportAddrs, ma.StringCast(fmt.Sprintf("/ip6/20%02x::04/udp/2/quic-v1/webtransport", 9-i))) + o.maybeRecordObservation(tcp6Conns[i], resTCPAddrs[idx]) + o.maybeRecordObservation(quic6Conns[i], resQuicAddrs[idx]) + o.maybeRecordObservation(webTransport6Conns[i], resWebTransportAddrs[idx]) + idx++ + } + var allAddrs []ma.Multiaddr + allAddrs = append(allAddrs, resTCPAddrs[:]...) + allAddrs = append(allAddrs, resQuicAddrs[:]...) + allAddrs = append(allAddrs, resWebTransportAddrs[:]...) + require.Eventually(t, func() bool { + return addrsEqual(o.Addrs(), allAddrs) + }, 1*time.Second, 100*time.Millisecond) + + for i := 0; i < N; i++ { + o.removeConn(tcp4Conns[i]) + o.removeConn(quic4Conns[i]) + o.removeConn(webTransport4Conns[i]) + o.removeConn(tcp6Conns[i]) + o.removeConn(quic6Conns[i]) + o.removeConn(webTransport6Conns[i]) + } + require.Eventually(t, func() bool { + return checkAllEntriesRemoved(o) + }, 1*time.Second, 100*time.Millisecond) + }) } -func TestEmitNATDeviceTypeSymmetric(t *testing.T) { - harness := newHarness(t) - require.Empty(t, harness.oas.Addrs()) - emitter, err := harness.host.EventBus().Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful) - require.NoError(t, err) - require.NoError(t, emitter.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate})) - - // TCP - it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232") - it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233") - it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234") - - // observers - b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236") - b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237") - b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237") - b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237") - - peers := []peer.ID{ - harness.add(b1), - harness.add(b2), - harness.add(b3), - harness.add(b4), +func genIPMultiaddr(ip6 bool) ma.Multiaddr { + var ipB [16]byte + crand.Read(ipB[:]) + var ip net.IP + if ip6 { + ip = net.IP(ipB[:]) + } else { + ip = net.IP(ipB[:4]) } - - harness.observe(it1, peers[0]) - harness.observe(it2, peers[1]) - harness.observe(it3, peers[2]) - harness.observe(it4, peers[3]) - - sub, err := harness.host.EventBus().Subscribe(new(event.EvtNATDeviceTypeChanged)) - require.NoError(t, err) - select { - case ev := <-sub.Out(): - evt := ev.(event.EvtNATDeviceTypeChanged) - require.Equal(t, network.NATDeviceTypeSymmetric, evt.NatDeviceType) - require.Equal(t, network.NATTransportTCP, evt.TransportProtocol) - case <-time.After(5 * time.Second): - t.Fatal("did not get Symmetric NAT event") - } - + addr, _ := manet.FromIP(ip) + return addr } -func TestEmitNATDeviceTypeCone(t *testing.T) { - harness := newHarness(t) - require.Empty(t, harness.oas.Addrs()) - emitter, err := harness.host.EventBus().Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful) - require.NoError(t, err) - require.NoError(t, emitter.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate})) - - it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1231") - - // observers - b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236") - b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237") - b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237") - b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237") - - peers := []peer.ID{ - harness.add(b1), - harness.add(b2), - harness.add(b3), - harness.add(b4), +func FuzzObservedAddrManager(f *testing.F) { + protos := []string{ + "/webrtc-direct", + "/quic-v1", + "/quic-v1/webtransport", + } + tcp4 := ma.StringCast("/ip4/192.168.1.100/tcp/1") + quic4 := ma.StringCast("/ip4/0.0.0.0/udp/1/quic-v1") + wt4 := ma.StringCast("/ip4/0.0.0.0/udp/1/quic-v1/webtransport/certhash/uEgNmb28") + tcp6 := ma.StringCast("/ip6/1::1/tcp/1") + quic6 := ma.StringCast("/ip6/::/udp/1/quic-v1") + wt6 := ma.StringCast("/ip6/::/udp/1/quic-v1/webtransport/certhash/uEgNmb28") + newObservedAddrMgr := func() *ObservedAddrManager { + listenAddrs := []ma.Multiaddr{ + tcp4, quic4, wt4, tcp6, quic6, wt6, + } + listenAddrsFunc := func() []ma.Multiaddr { + return listenAddrs + } + interfaceListenAddrsFunc := func() ([]ma.Multiaddr, error) { + return listenAddrs, nil + } + o, err := NewObservedAddrManager(listenAddrsFunc, listenAddrsFunc, + interfaceListenAddrsFunc, normalize) + if err != nil { + panic(err) + } + return o } - harness.observe(it1, peers[0]) - harness.observe(it2, peers[1]) - harness.observe(it3, peers[2]) - harness.observe(it4, peers[3]) + f.Fuzz(func(t *testing.T, port uint16) { + addrs := []ma.Multiaddr{genIPMultiaddr(true), genIPMultiaddr(false)} + n := len(addrs) + for i := 0; i < n; i++ { + addrs = append(addrs, addrs[i].Encapsulate(ma.StringCast(fmt.Sprintf("/tcp/%d", port)))) + addrs = append(addrs, addrs[i].Encapsulate(ma.StringCast(fmt.Sprintf("/udp/%d", port)))) + addrs = append(addrs, ma.StringCast(fmt.Sprintf("/tcp/%d", port))) + addrs = append(addrs, ma.StringCast(fmt.Sprintf("/udp/%d", port))) + } + n = len(addrs) + for i := 0; i < n; i++ { + for j := 0; j < len(protos); j++ { + protoAddr := ma.StringCast(protos[j]) + addrs = append(addrs, addrs[i].Encapsulate(protoAddr)) + addrs = append(addrs, protoAddr) + } + } + o := newObservedAddrMgr() + defer o.Close() + for i := 0; i < len(addrs); i++ { + for _, l := range o.listenAddrs() { + c := newConn(l, addrs[i]) + o.maybeRecordObservation(c, addrs[i]) + o.maybeRecordObservation(c, nil) + o.maybeRecordObservation(nil, addrs[i]) + o.removeConn(c) + } + } + }) +} - sub, err := harness.host.EventBus().Subscribe(new(event.EvtNATDeviceTypeChanged)) - require.NoError(t, err) - select { - case ev := <-sub.Out(): - evt := ev.(event.EvtNATDeviceTypeChanged) - require.Equal(t, network.NATDeviceTypeCone, evt.NatDeviceType) - case <-time.After(5 * time.Second): - t.Fatal("did not get Cone NAT event") +func TestObserver(t *testing.T) { + tests := []struct { + addr ma.Multiaddr + want string + }{ + { + addr: ma.StringCast("/ip4/1.2.3.4/tcp/1"), + want: "1.2.3.4", + }, + { + addr: ma.StringCast("/ip4/192.168.0.1/tcp/1"), + want: "192.168.0.1", + }, + { + addr: ma.StringCast("/ip6/200::1/udp/1/quic-v1"), + want: "200::", + }, + { + addr: ma.StringCast("/ip6/::1/udp/1/quic-v1"), + want: "::", + }, + } + + for i, tc := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + got, err := getObserver(tc.addr) + require.NoError(t, err) + require.Equal(t, got, tc.want) + }) } } - -func TestObserveWebtransport(t *testing.T) { - listenAddr := ma.StringCast("/ip4/1.2.3.4/udp/9999/quic-v1/webtransport/certhash/uEgNmb28") - observedAddr := ma.StringCast("/ip4/1.2.3.4/udp/1231/quic-v1/webtransport") - - harness := newHarnessWithMa(t, listenAddr) - - pb1 := harness.add(ma.StringCast("/ip4/1.2.3.6/udp/1236/quic-v1/webtransport")) - pb2 := harness.add(ma.StringCast("/ip4/1.2.3.7/udp/1237/quic-v1/webtransport")) - pb3 := harness.add(ma.StringCast("/ip4/1.2.3.8/udp/1237/quic-v1/webtransport")) - pb4 := harness.add(ma.StringCast("/ip4/1.2.3.9/udp/1237/quic-v1/webtransport")) - pb5 := harness.add(ma.StringCast("/ip4/1.2.3.10/udp/1237/quic-v1/webtransport")) - - harness.observe(observedAddr, pb1) - harness.observe(observedAddr, pb2) - harness.observe(observedAddr, pb3) - harness.observe(observedAddr, pb4) - harness.observe(observedAddr, pb5) - - require.Equal(t, 1, len(harness.oas.Addrs())) - require.Equal(t, "/ip4/1.2.3.4/udp/1231/quic-v1/webtransport", harness.oas.Addrs()[0].String()) -} diff --git a/go-libp2p/p2p/protocol/identify/opts.go b/go-libp2p/p2p/protocol/identify/opts.go index f188665..bd0fd89 100644 --- a/go-libp2p/p2p/protocol/identify/opts.go +++ b/go-libp2p/p2p/protocol/identify/opts.go @@ -1,10 +1,11 @@ package identify type config struct { - protocolVersion string - userAgent string - disableSignedPeerRecord bool - metricsTracer MetricsTracer + protocolVersion string + userAgent string + disableSignedPeerRecord bool + metricsTracer MetricsTracer + disableObservedAddrManager bool } // Option is an option function for identify. @@ -38,3 +39,11 @@ func WithMetricsTracer(tr MetricsTracer) Option { cfg.metricsTracer = tr } } + +// DisableObservedAddrManager disables the observed address manager. It also +// effectively disables the nat emitter and EvtNATDeviceTypeChanged +func DisableObservedAddrManager() Option { + return func(cfg *config) { + cfg.disableObservedAddrManager = true + } +} diff --git a/go-libp2p/p2p/protocol/ping/ping.go b/go-libp2p/p2p/protocol/ping/ping.go index 6ff5c3f..9a67715 100644 --- a/go-libp2p/p2p/protocol/ping/ping.go +++ b/go-libp2p/p2p/protocol/ping/ping.go @@ -111,7 +111,7 @@ func pingError(err error) chan Result { // Ping pings the remote peer until the context is canceled, returning a stream // of RTTs or errors. func Ping(ctx context.Context, h host.Host, p peer.ID) <-chan Result { - s, err := h.NewStream(network.WithUseTransient(ctx, "ping"), p, ID) + s, err := h.NewStream(network.WithAllowLimitedConn(ctx, "ping"), p, ID) if err != nil { return pingError(err) } @@ -158,11 +158,10 @@ func Ping(ctx context.Context, h host.Host, p peer.ID) <-chan Result { } } }() - go func() { + context.AfterFunc(ctx, func() { // forces the ping to abort. - <-ctx.Done() s.Reset() - }() + }) return out } diff --git a/go-libp2p/p2p/security/noise/LICENSE.md b/go-libp2p/p2p/security/noise/LICENSE.md deleted file mode 100644 index 15601cb..0000000 --- a/go-libp2p/p2p/security/noise/LICENSE.md +++ /dev/null @@ -1,229 +0,0 @@ -The contents of this repository are Copyright (c) corresponding authors and -contributors, licensed under the `Permissive License Stack` meaning either of: - -- Apache-2.0 Software License: https://www.apache.org/licenses/LICENSE-2.0 - ([...4tr2kfsq](https://gateway.ipfs.io/ipfs/bafkreiankqxazcae4onkp436wag2lj3ccso4nawxqkkfckd6cg4tr2kfsq)) - -- MIT Software License: https://opensource.org/licenses/MIT - ([...vljevcba](https://gateway.ipfs.io/ipfs/bafkreiepofszg4gfe2gzuhojmksgemsub2h4uy2gewdnr35kswvljevcba)) - -You may not use the contents of this repository except in compliance -with one of the listed Licenses. For an extended clarification of the -intent behind the choice of Licensing please refer to -https://protocol.ai/blog/announcing-the-permissive-license-stack/ - -Unless required by applicable law or agreed to in writing, software -distributed under the terms listed in this notice is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -either express or implied. See each License for the specific language -governing permissions and limitations under that License. - - -`SPDX-License-Identifier: Apache-2.0 OR MIT` - -Verbatim copies of both licenses are included below: - -
Apache-2.0 Software License - -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS -``` -
- -
MIT Software License - -``` -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -``` -
diff --git a/go-libp2p/p2p/security/noise/handshake.go b/go-libp2p/p2p/security/noise/handshake.go index e1a18e9..4760768 100644 --- a/go-libp2p/p2p/security/noise/handshake.go +++ b/go-libp2p/p2p/security/noise/handshake.go @@ -5,18 +5,17 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "hash" "os" "runtime/debug" "time" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/sec" "github.com/libp2p/go-libp2p/p2p/security/noise/pb" "github.com/flynn/noise" pool "github.com/libp2p/go-buffer-pool" - "github.com/minio/sha256-simd" "google.golang.org/protobuf/proto" ) @@ -26,15 +25,8 @@ import ( // our libp2p identity key. const payloadSigPrefix = "noise-libp2p-static-key:" -type minioSHAFn struct{} - -func (h minioSHAFn) Hash() hash.Hash { return sha256.New() } -func (h minioSHAFn) HashName() string { return "SHA256" } - -var shaHashFn noise.HashFunc = minioSHAFn{} - // All noise session share a fixed cipher suite -var cipherSuite = noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, shaHashFn) +var cipherSuite = noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256) // runHandshake exchanges handshake messages with the remote peer to establish // a noise-libp2p session. It blocks until the handshake completes or fails. @@ -276,7 +268,7 @@ func (s *secureSession) handleRemoteHandshakePayload(payload []byte, remoteStati // check the peer ID if enabled if s.checkPeerID && s.remoteID != id { - return nil, fmt.Errorf("peer id mismatch: expected %s, but remote key matches %s", s.remoteID.Pretty(), id.Pretty()) + return nil, sec.ErrPeerIDMismatch{Expected: s.remoteID, Actual: id} } // verify payload is signed by asserted remote libp2p key. diff --git a/go-libp2p/p2p/security/noise/transport_test.go b/go-libp2p/p2p/security/noise/transport_test.go index 42477f8..ea7916f 100644 --- a/go-libp2p/p2p/security/noise/transport_test.go +++ b/go-libp2p/p2p/security/noise/transport_test.go @@ -182,16 +182,16 @@ func TestPeerIDMatch(t *testing.T) { defer close(done) conn, err := initTransport.SecureOutbound(context.Background(), init, respTransport.localID) assert.NoError(t, err) - assert.Equal(t, conn.RemotePeer(), respTransport.localID) + assert.Equal(t, respTransport.localID, conn.RemotePeer()) b := make([]byte, 6) _, err = conn.Read(b) assert.NoError(t, err) - assert.Equal(t, b, []byte("foobar")) + assert.Equal(t, []byte("foobar"), b) }() conn, err := respTransport.SecureInbound(context.Background(), resp, initTransport.localID) require.NoError(t, err) - require.Equal(t, conn.RemotePeer(), initTransport.localID) + require.Equal(t, initTransport.localID, conn.RemotePeer()) _, err = conn.Write([]byte("foobar")) require.NoError(t, err) } @@ -212,7 +212,10 @@ func TestPeerIDMismatchOutboundFailsHandshake(t *testing.T) { initErr := <-errChan require.Error(t, initErr, "expected initiator to fail with peer ID mismatch error") - require.Contains(t, initErr.Error(), "but remote key matches") + var mismatchErr sec.ErrPeerIDMismatch + require.ErrorAs(t, initErr, &mismatchErr) + require.Equal(t, mismatchErr.Expected, peer.ID("a-random-peer-id")) + require.Equal(t, mismatchErr.Actual, respTransport.localID) } func TestPeerIDMismatchInboundFailsHandshake(t *testing.T) { @@ -231,6 +234,10 @@ func TestPeerIDMismatchInboundFailsHandshake(t *testing.T) { _, err := respTransport.SecureInbound(context.Background(), resp, "a-random-peer-id") require.Error(t, err, "expected responder to fail with peer ID mismatch error") + var mismatchErr sec.ErrPeerIDMismatch + require.ErrorAs(t, err, &mismatchErr) + require.Equal(t, mismatchErr.Expected, peer.ID("a-random-peer-id")) + require.Equal(t, mismatchErr.Actual, initTransport.localID) <-done } @@ -347,7 +354,7 @@ func TestBufferEqEncPayload(t *testing.T) { afterLen, err := respConn.Read(after) require.NoError(t, err) - require.Equal(t, len(before), afterLen) + require.Len(t, before, afterLen) require.Equal(t, before, after[:len(before)]) } @@ -367,7 +374,7 @@ func TestBufferEqDecryptedPayload(t *testing.T) { afterLen, err := respConn.Read(after) require.NoError(t, err) - require.Equal(t, len(before), afterLen) + require.Len(t, before, afterLen) require.Equal(t, before, after[:len(before)]) } @@ -386,7 +393,7 @@ func TestReadUnencryptedFails(t *testing.T) { copy(msg[LengthPrefixLength:], before) n, err := initConn.insecureConn.Write(msg) require.NoError(t, err) - require.Equal(t, len(msg), n) + require.Len(t, msg, n) after := make([]byte, len(msg)+1) afterLen, err := respConn.Read(after) @@ -407,7 +414,7 @@ func TestReadUnencryptedFails(t *testing.T) { copy(msg[LengthPrefixLength:], before) n, err = initConn.insecureConn.Write(msg) require.NoError(t, err) - require.Equal(t, len(msg), n) + require.Len(t, msg, n) after = make([]byte, 1) afterLen, err = respConn.Read(after) @@ -588,7 +595,6 @@ func TestEarlyDataRejected(t *testing.T) { clientErr, serverErr := handshake(t, sendingEDH, receivingEDH) require.Error(t, clientErr) require.EqualError(t, serverErr, "nope") - }) t.Run("server sending", func(t *testing.T) { diff --git a/go-libp2p/p2p/security/tls/LICENSE.md b/go-libp2p/p2p/security/tls/LICENSE.md deleted file mode 100644 index a94e82c..0000000 --- a/go-libp2p/p2p/security/tls/LICENSE.md +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2018 Marten Seemann - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/go-libp2p/p2p/security/tls/cmd/tlsdiag/client.go b/go-libp2p/p2p/security/tls/cmd/tlsdiag/client.go index 3868afe..a29189a 100644 --- a/go-libp2p/p2p/security/tls/cmd/tlsdiag/client.go +++ b/go-libp2p/p2p/security/tls/cmd/tlsdiag/client.go @@ -33,7 +33,7 @@ func StartClient() error { if err != nil { return err } - fmt.Printf(" Peer ID: %s\n", id.Pretty()) + fmt.Printf(" Peer ID: %s\n", id) tp, err := libp2ptls.New(libp2ptls.ID, priv, nil) if err != nil { return err @@ -53,7 +53,7 @@ func StartClient() error { if err != nil { return err } - fmt.Printf("Authenticated server: %s\n", sconn.RemotePeer().Pretty()) + fmt.Printf("Authenticated server: %s\n", sconn.RemotePeer()) data, err := io.ReadAll(sconn) if err != nil { return err diff --git a/go-libp2p/p2p/security/tls/cmd/tlsdiag/server.go b/go-libp2p/p2p/security/tls/cmd/tlsdiag/server.go index 76c45a1..cd702a7 100644 --- a/go-libp2p/p2p/security/tls/cmd/tlsdiag/server.go +++ b/go-libp2p/p2p/security/tls/cmd/tlsdiag/server.go @@ -26,7 +26,7 @@ func StartServer() error { if err != nil { return err } - fmt.Printf(" Peer ID: %s\n", id.Pretty()) + fmt.Printf(" Peer ID: %s\n", id) tp, err := libp2ptls.New(libp2ptls.ID, priv, nil) if err != nil { return err @@ -38,7 +38,7 @@ func StartServer() error { } fmt.Printf("Listening for new connections on %s\n", ln.Addr()) fmt.Printf("Now run the following command in a separate terminal:\n") - fmt.Printf("\tgo run cmd/tlsdiag.go client -p %d -id %s\n", *port, id.Pretty()) + fmt.Printf("\tgo run cmd/tlsdiag.go client -p %d -id %s\n", *port, id) for { conn, err := ln.Accept() @@ -61,7 +61,7 @@ func handleConn(tp *libp2ptls.Transport, conn net.Conn) error { if err != nil { return err } - fmt.Printf("Authenticated client: %s\n", sconn.RemotePeer().Pretty()) + fmt.Printf("Authenticated client: %s\n", sconn.RemotePeer()) fmt.Fprintf(sconn, "Hello client!") fmt.Printf("Closing connection to %s\n", conn.RemoteAddr()) return sconn.Close() diff --git a/go-libp2p/p2p/security/tls/crypto.go b/go-libp2p/p2p/security/tls/crypto.go index b8f23f3..70a594d 100644 --- a/go-libp2p/p2p/security/tls/crypto.go +++ b/go-libp2p/p2p/security/tls/crypto.go @@ -11,6 +11,7 @@ import ( "encoding/asn1" "errors" "fmt" + "io" "math/big" "os" "runtime/debug" @@ -18,6 +19,7 @@ import ( ic "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/sec" ) const certValidityPeriod = 100 * 365 * 24 * time.Hour // ~100 years @@ -40,6 +42,7 @@ type Identity struct { // IdentityConfig is used to configure an Identity type IdentityConfig struct { CertTemplate *x509.Certificate + KeyLogWriter io.Writer } // IdentityOption transforms an IdentityConfig to apply optional settings. @@ -52,6 +55,18 @@ func WithCertTemplate(template *x509.Certificate) IdentityOption { } } +// WithKeyLogWriter optionally specifies a destination for TLS master secrets +// in NSS key log format that can be used to allow external programs +// such as Wireshark to decrypt TLS connections. +// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. +// Use of KeyLogWriter compromises security and should only be +// used for debugging. +func WithKeyLogWriter(w io.Writer) IdentityOption { + return func(c *IdentityConfig) { + c.KeyLogWriter = w + } +} + // NewIdentity creates a new identity func NewIdentity(privKey ic.PrivKey, opts ...IdentityOption) (*Identity, error) { config := IdentityConfig{} @@ -82,6 +97,7 @@ func NewIdentity(privKey ic.PrivKey, opts ...IdentityOption) (*Identity, error) }, NextProtos: []string{alpn}, SessionTicketsDisabled: true, + KeyLogWriter: config.KeyLogWriter, }, }, nil } @@ -129,7 +145,7 @@ func (i *Identity) ConfigForPeer(remote peer.ID) (*tls.Config, <-chan ic.PubKey) if err != nil { peerID = peer.ID(fmt.Sprintf("(not determined: %s)", err.Error())) } - return fmt.Errorf("peer IDs don't match: expected %s, got %s", remote, peerID) + return sec.ErrPeerIDMismatch{Expected: remote, Actual: peerID} } keyCh <- pubKey return nil diff --git a/go-libp2p/p2p/security/tls/crypto_test.go b/go-libp2p/p2p/security/tls/crypto_test.go index 872f588..efec949 100644 --- a/go-libp2p/p2p/security/tls/crypto_test.go +++ b/go-libp2p/p2p/security/tls/crypto_test.go @@ -19,31 +19,31 @@ func TestNewIdentityCertificates(t *testing.T) { t.Run("NewIdentity with default template", func(t *testing.T) { // Generate an identity using the default template id, err := NewIdentity(key) - assert.NoError(t, err) + require.NoError(t, err) // Extract the x509 certificate x509Cert, err := x509.ParseCertificate(id.config.Certificates[0].Certificate[0]) - assert.NoError(t, err) + require.NoError(t, err) // verify the common name and email are not set - assert.Empty(t, x509Cert.Subject.CommonName) - assert.Empty(t, x509Cert.EmailAddresses) + require.Empty(t, x509Cert.Subject.CommonName) + require.Empty(t, x509Cert.EmailAddresses) }) t.Run("NewIdentity with custom template", func(t *testing.T) { tmpl, err := certTemplate() - assert.NoError(t, err) + require.NoError(t, err) tmpl.Subject.CommonName = cn tmpl.EmailAddresses = []string{email} // Generate an identity using the custom template id, err := NewIdentity(key, WithCertTemplate(tmpl)) - assert.NoError(t, err) + require.NoError(t, err) // Extract the x509 certificate x509Cert, err := x509.ParseCertificate(id.config.Certificates[0].Certificate[0]) - assert.NoError(t, err) + require.NoError(t, err) // verify the common name and email are set assert.Equal(t, cn, x509Cert.Subject.CommonName) diff --git a/go-libp2p/p2p/security/tls/extension_test.go b/go-libp2p/p2p/security/tls/extension_test.go index f50695a..6bed725 100644 --- a/go-libp2p/p2p/security/tls/extension_test.go +++ b/go-libp2p/p2p/security/tls/extension_test.go @@ -7,7 +7,7 @@ import ( ) func TestExtensionGenerating(t *testing.T) { - require.Equal(t, getPrefixedExtensionID([]int{13, 37}), []int{1, 3, 6, 1, 4, 1, 53594, 13, 37}) + require.Equal(t, []int{1, 3, 6, 1, 4, 1, 53594, 13, 37}, getPrefixedExtensionID([]int{13, 37})) } func TestExtensionComparison(t *testing.T) { diff --git a/go-libp2p/p2p/security/tls/transport.go b/go-libp2p/p2p/security/tls/transport.go index 7c28efe..0c494a7 100644 --- a/go-libp2p/p2p/security/tls/transport.go +++ b/go-libp2p/p2p/security/tls/transport.go @@ -113,7 +113,7 @@ func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p pee for _, muxer := range t.muxers { muxers = append(muxers, (string)(muxer)) } - // Prepend the prefered muxers list to TLS config. + // Prepend the preferred muxers list to TLS config. config.NextProtos = append(muxers, config.NextProtos...) cs, err := t.handshake(ctx, tls.Client(insecure, config), keyCh) if err != nil { diff --git a/go-libp2p/p2p/security/tls/transport_test.go b/go-libp2p/p2p/security/tls/transport_test.go index 2d3c2d9..b53d9bf 100644 --- a/go-libp2p/p2p/security/tls/transport_test.go +++ b/go-libp2p/p2p/security/tls/transport_test.go @@ -46,7 +46,7 @@ func createPeer(t *testing.T) (peer.ID, ic.PrivKey) { require.NoError(t, err) id, err := peer.IDFromPrivateKey(priv) require.NoError(t, err) - t.Logf("using a %s key: %s", priv.Type(), id.Pretty()) + t.Logf("using a %s key: %s", priv.Type(), id) return id, priv } @@ -121,7 +121,7 @@ func TestHandshakeSucceeds(t *testing.T) { b := make([]byte, 6) _, err = clientConn.Read(b) require.NoError(t, err) - require.Equal(t, string(b), "foobar") + require.Equal(t, "foobar", string(b)) } // Use standard transports with default TLS configuration @@ -245,21 +245,21 @@ func TestHandshakeWithNextProtoSucceeds(t *testing.T) { } defer serverConn.Close() - require.Equal(t, clientConn.LocalPeer(), clientID) - require.Equal(t, serverConn.LocalPeer(), serverID) - require.Equal(t, clientConn.RemotePeer(), serverID) - require.Equal(t, serverConn.RemotePeer(), clientID) + require.Equal(t, clientID, clientConn.LocalPeer()) + require.Equal(t, serverID, serverConn.LocalPeer()) + require.Equal(t, serverID, clientConn.RemotePeer()) + require.Equal(t, clientID, serverConn.RemotePeer()) require.True(t, clientConn.RemotePublicKey().Equals(serverKey.GetPublic()), "server public key mismatch") require.True(t, serverConn.RemotePublicKey().Equals(clientKey.GetPublic()), "client public key mismatch") - require.Equal(t, clientConn.ConnState().StreamMultiplexer, expectedMuxer) - require.Equal(t, clientConn.ConnState().UsedEarlyMuxerNegotiation, expectedMuxer != "") + require.Equal(t, expectedMuxer, clientConn.ConnState().StreamMultiplexer) + require.Equal(t, expectedMuxer != "", clientConn.ConnState().UsedEarlyMuxerNegotiation) // exchange some data _, err = serverConn.Write([]byte("foobar")) require.NoError(t, err) b := make([]byte, 6) _, err = clientConn.Read(b) require.NoError(t, err) - require.Equal(t, string(b), "foobar") + require.Equal(t, "foobar", string(b)) } // Iterate through the StreamMultiplexer combinations. @@ -376,7 +376,10 @@ func TestPeerIDMismatch(t *testing.T) { thirdPartyID, _ := createPeer(t) _, err = clientTransport.SecureOutbound(context.Background(), clientInsecureConn, thirdPartyID) require.Error(t, err) - require.Contains(t, err.Error(), "peer IDs don't match") + var mismatchErr sec.ErrPeerIDMismatch + require.ErrorAs(t, err, &mismatchErr) + require.Equal(t, mismatchErr.Expected, thirdPartyID) + require.Equal(t, mismatchErr.Actual, serverID) var serverErr error select { @@ -392,8 +395,8 @@ func TestPeerIDMismatch(t *testing.T) { clientInsecureConn, serverInsecureConn := connect(t) errChan := make(chan error) + thirdPartyID, _ := createPeer(t) go func() { - thirdPartyID, _ := createPeer(t) // expect the wrong peer ID _, err := serverTransport.SecureInbound(context.Background(), serverInsecureConn, thirdPartyID) errChan <- err @@ -412,7 +415,10 @@ func TestPeerIDMismatch(t *testing.T) { t.Fatal("expected handshake to return on the server side") } require.Error(t, serverErr) - require.Contains(t, serverErr.Error(), "peer IDs don't match") + var mismatchErr sec.ErrPeerIDMismatch + require.ErrorAs(t, serverErr, &mismatchErr) + require.Equal(t, mismatchErr.Expected, thirdPartyID) + require.Equal(t, mismatchErr.Actual, clientTransport.localPeer) }) } diff --git a/go-libp2p/p2p/test/basichost/basic_host_test.go b/go-libp2p/p2p/test/basichost/basic_host_test.go index 6b010ed..9cd442d 100644 --- a/go-libp2p/p2p/test/basichost/basic_host_test.go +++ b/go-libp2p/p2p/test/basichost/basic_host_test.go @@ -3,14 +3,20 @@ package basichost import ( "context" "fmt" + "strings" "testing" + "time" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -18,12 +24,14 @@ func TestNoStreamOverTransientConnection(t *testing.T) { h1, err := libp2p.New( libp2p.NoListenAddrs, libp2p.EnableRelay(), + libp2p.ResourceManager(&network.NullResourceManager{}), ) require.NoError(t, err) h2, err := libp2p.New( libp2p.NoListenAddrs, libp2p.EnableRelay(), + libp2p.ResourceManager(&network.NullResourceManager{}), ) require.NoError(t, err) @@ -62,11 +70,132 @@ func TestNoStreamOverTransientConnection(t *testing.T) { err = h1.Connect(context.Background(), h2Info) require.NoError(t, err) - ctx := network.WithNoDial(context.Background(), "test") + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + ctx = network.WithNoDial(ctx, "test") _, err = h1.NewStream(ctx, h2.ID(), "/testprotocol") - require.ErrorIs(t, err, network.ErrTransientConn) + require.Error(t, err) - _, err = h1.NewStream(network.WithUseTransient(context.Background(), "test"), h2.ID(), "/testprotocol") + _, err = h1.NewStream(network.WithAllowLimitedConn(context.Background(), "test"), h2.ID(), "/testprotocol") require.NoError(t, err) } + +func TestNewStreamTransientConnection(t *testing.T) { + h1, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + libp2p.EnableRelay(), + libp2p.ResourceManager(&network.NullResourceManager{}), + ) + require.NoError(t, err) + + h2, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + libp2p.EnableRelay(), + libp2p.ResourceManager(&network.NullResourceManager{}), + ) + require.NoError(t, err) + + relay1, err := libp2p.New() + require.NoError(t, err) + + _, err = relay.New(relay1) + require.NoError(t, err) + + relay1info := peer.AddrInfo{ + ID: relay1.ID(), + Addrs: relay1.Addrs(), + } + err = h1.Connect(context.Background(), relay1info) + require.NoError(t, err) + + err = h2.Connect(context.Background(), relay1info) + require.NoError(t, err) + + h2.SetStreamHandler("/testprotocol", func(s network.Stream) { + fmt.Println("testprotocol") + + // End the example + s.Close() + }) + + _, err = client.Reserve(context.Background(), h2, relay1info) + require.NoError(t, err) + + relayaddr := ma.StringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String()) + + h1.Peerstore().AddAddr(h2.ID(), relayaddr, peerstore.TempAddrTTL) + + // NewStream should block transient connections till we have a direct connection + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + s, err := h1.NewStream(ctx, h2.ID(), "/testprotocol") + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Nil(t, s) + + // NewStream should return a stream if a direct connection is established + // while waiting + done := make(chan bool, 2) + go func() { + h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.TempAddrTTL) + ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = network.WithNoDial(ctx, "test") + s, err = h1.NewStream(ctx, h2.ID(), "/testprotocol") + require.NoError(t, err) + require.NotNil(t, s) + defer s.Close() + require.Equal(t, network.DirInbound, s.Conn().Stat().Direction) + done <- true + }() + go func() { + // connect h2 to h1 simulating connection reversal + h2.Peerstore().AddAddrs(h1.ID(), h1.Addrs(), peerstore.TempAddrTTL) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + ctx = network.WithForceDirectDial(ctx, "test") + err := h2.Connect(ctx, peer.AddrInfo{ID: h1.ID()}) + assert.NoError(t, err) + done <- true + }() + <-done + <-done +} + +func TestAddrFactorCertHashAppend(t *testing.T) { + wtAddr := "/ip4/1.2.3.4/udp/1/quic-v1/webtransport" + webrtcAddr := "/ip4/1.2.3.4/udp/2/webrtc-direct" + addrsFactory := func(addrs []ma.Multiaddr) []ma.Multiaddr { + return append(addrs, + ma.StringCast(wtAddr), + ma.StringCast(webrtcAddr), + ) + } + h, err := libp2p.New( + libp2p.AddrsFactory(addrsFactory), + libp2p.Transport(libp2pwebrtc.New), + libp2p.Transport(libp2pwebtransport.New), + libp2p.ListenAddrStrings( + "/ip4/0.0.0.0/udp/0/quic-v1/webtransport", + "/ip4/0.0.0.0/udp/0/webrtc-direct", + ), + ) + require.NoError(t, err) + require.Eventually(t, func() bool { + addrs := h.Addrs() + var hasWebRTC, hasWebTransport bool + for _, addr := range addrs { + if strings.HasPrefix(addr.String(), webrtcAddr) { + if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err == nil { + hasWebRTC = true + } + } + if strings.HasPrefix(addr.String(), wtAddr) { + if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err == nil { + hasWebTransport = true + } + } + } + return hasWebRTC && hasWebTransport + }, 5*time.Second, 100*time.Millisecond) +} diff --git a/go-libp2p/p2p/test/negotiation/muxer_test.go b/go-libp2p/p2p/test/negotiation/muxer_test.go index 9301e66..52c6622 100644 --- a/go-libp2p/p2p/test/negotiation/muxer_test.go +++ b/go-libp2p/p2p/test/negotiation/muxer_test.go @@ -11,7 +11,6 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/sec/insecure" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" "github.com/libp2p/go-libp2p/p2p/security/noise" tls "github.com/libp2p/go-libp2p/p2p/security/tls" @@ -21,8 +20,8 @@ import ( ) var ( - yamuxOpt = libp2p.Muxer("/yamux", yamux.DefaultTransport) - mplexOpt = libp2p.Muxer("/mplex", mplex.DefaultTransport) + yamuxOpt = libp2p.Muxer("/yamux", yamux.DefaultTransport) + anotherYamuxOpt = libp2p.Muxer("/another-yamux", yamux.DefaultTransport) ) type testcase struct { @@ -43,32 +42,32 @@ func TestMuxerNegotiation(t *testing.T) { testcases := []testcase{ { Name: "server and client have the same preference", - ServerPreference: []libp2p.Option{yamuxOpt, mplexOpt}, - ClientPreference: []libp2p.Option{yamuxOpt, mplexOpt}, + ServerPreference: []libp2p.Option{yamuxOpt, anotherYamuxOpt}, + ClientPreference: []libp2p.Option{yamuxOpt, anotherYamuxOpt}, Expected: "/yamux", }, { Name: "client only supports one muxer", - ServerPreference: []libp2p.Option{yamuxOpt, mplexOpt}, + ServerPreference: []libp2p.Option{yamuxOpt, anotherYamuxOpt}, ClientPreference: []libp2p.Option{yamuxOpt}, Expected: "/yamux", }, { Name: "server only supports one muxer", ServerPreference: []libp2p.Option{yamuxOpt}, - ClientPreference: []libp2p.Option{mplexOpt, yamuxOpt}, + ClientPreference: []libp2p.Option{anotherYamuxOpt, yamuxOpt}, Expected: "/yamux", }, { Name: "client preference preferred", - ServerPreference: []libp2p.Option{yamuxOpt, mplexOpt}, - ClientPreference: []libp2p.Option{mplexOpt, yamuxOpt}, - Expected: "/mplex", + ServerPreference: []libp2p.Option{yamuxOpt, anotherYamuxOpt}, + ClientPreference: []libp2p.Option{anotherYamuxOpt, yamuxOpt}, + Expected: "/another-yamux", }, { Name: "no preference overlap", ServerPreference: []libp2p.Option{yamuxOpt}, - ClientPreference: []libp2p.Option{mplexOpt}, + ClientPreference: []libp2p.Option{anotherYamuxOpt}, Error: "failed to negotiate stream multiplexer: protocols not supported", }, } diff --git a/go-libp2p/p2p/test/notifications/notification_test.go b/go-libp2p/p2p/test/notifications/notification_test.go index b6159ac..eb26a3f 100644 --- a/go-libp2p/p2p/test/notifications/notification_test.go +++ b/go-libp2p/p2p/test/notifications/notification_test.go @@ -41,7 +41,7 @@ func TestListenAddressNotif(t *testing.T) { ev := e.(event.EvtLocalAddressesUpdated) require.Empty(t, ev.Removed) require.Len(t, ev.Current, 1) - require.Equal(t, ev.Current[0].Action, event.Added) + require.Equal(t, event.Added, ev.Current[0].Action) initialAddr = ev.Current[0].Address portStr, err := initialAddr.ValueForProtocol(ma.P_TCP) require.NoError(t, err) diff --git a/go-libp2p/p2p/test/quic/quic_test.go b/go-libp2p/p2p/test/quic/quic_test.go index 0603c89..fe52119 100644 --- a/go-libp2p/p2p/test/quic/quic_test.go +++ b/go-libp2p/p2p/test/quic/quic_test.go @@ -26,103 +26,12 @@ func getQUICMultiaddrCode(addr ma.Multiaddr) int { return 0 } -func TestQUICVersions(t *testing.T) { - h1, err := libp2p.New( - libp2p.Transport(libp2pquic.NewTransport), - libp2p.Transport(webtransport.New), - libp2p.ListenAddrStrings( - "/ip4/127.0.0.1/udp/12345/quic", // QUIC draft-29 - "/ip4/127.0.0.1/udp/12345/quic-v1", // QUIC v1 - ), - ) - require.NoError(t, err) - defer h1.Close() - - addrs := h1.Addrs() - require.Len(t, addrs, 2) - var quicDraft29Addr, quicV1Addr ma.Multiaddr - for _, addr := range addrs { - switch getQUICMultiaddrCode(addr) { - case ma.P_QUIC: - quicDraft29Addr = addr - case ma.P_QUIC_V1: - quicV1Addr = addr - } - } - require.NotNil(t, quicDraft29Addr, "expected to be listening on a QUIC draft-29 address") - require.NotNil(t, quicV1Addr, "expected to be listening on a QUIC v1 address") - - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() - // connect using QUIC draft-29 - h2, err := libp2p.New( - libp2p.Transport(libp2pquic.NewTransport), - ) - require.NoError(t, err) - require.NoError(t, h2.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{quicDraft29Addr}})) - conns := h2.Network().ConnsToPeer(h1.ID()) - require.Len(t, conns, 1) - require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) - require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) - h2.Close() - - // connect using QUIC v1 - h3, err := libp2p.New( - libp2p.Transport(libp2pquic.NewTransport), - ) - require.NoError(t, err) - require.NoError(t, h3.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{quicV1Addr}})) - conns = h3.Network().ConnsToPeer(h1.ID()) - require.Len(t, conns, 1) - require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) - require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) - h3.Close() -} - -func TestDisableQUICDraft29(t *testing.T) { - h1, err := libp2p.New( - libp2p.QUICReuse(quicreuse.NewConnManager, quicreuse.DisableDraft29()), - libp2p.Transport(libp2pquic.NewTransport), - libp2p.Transport(webtransport.New), - libp2p.ListenAddrStrings( - "/ip4/127.0.0.1/udp/12346/quic", // QUIC draft-29 - "/ip4/127.0.0.1/udp/12346/quic-v1", // QUIC v1 - ), - ) - require.NoError(t, err) - defer h1.Close() - - addrs := h1.Addrs() - require.Len(t, addrs, 1) - require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(addrs[0])) - - // connect using QUIC draft-29 - h2, err := libp2p.New( - libp2p.Transport(libp2pquic.NewTransport), - ) - require.NoError(t, err) - defer h2.Close() - // We disabled QUIC Version Negotiation, so we will _not_ receive a Version Negotiation packet. - // Instead, the connection will run into the context timeout. - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - require.ErrorIs(t, - h2.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/udp/12346/quic")}}), - context.DeadlineExceeded, - ) - // make sure that dialing QUIC v1 works - ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - require.NoError(t, h2.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{addrs[0]}})) -} - func TestQUICAndWebTransport(t *testing.T) { h1, err := libp2p.New( libp2p.QUICReuse(quicreuse.NewConnManager), libp2p.Transport(libp2pquic.NewTransport), libp2p.Transport(webtransport.New), libp2p.ListenAddrStrings( - "/ip4/127.0.0.1/udp/12347/quic/", "/ip4/127.0.0.1/udp/12347/quic-v1", "/ip4/127.0.0.1/udp/12347/quic-v1/webtransport", ), @@ -131,19 +40,16 @@ func TestQUICAndWebTransport(t *testing.T) { defer h1.Close() addrs := h1.Addrs() - require.Len(t, addrs, 3) - var quicDraft29Addr, quicV1Addr, webtransportAddr ma.Multiaddr + require.Len(t, addrs, 2) + var quicV1Addr, webtransportAddr ma.Multiaddr for _, addr := range addrs { if _, err := addr.ValueForProtocol(ma.P_WEBTRANSPORT); err == nil { webtransportAddr = addr } else if _, err := addr.ValueForProtocol(ma.P_QUIC_V1); err == nil { quicV1Addr = addr - } else { - quicDraft29Addr = addr } } require.NotNil(t, webtransportAddr, "expected to have a WebTransport address") - require.NotNil(t, quicDraft29Addr, "expected to have a QUIC draft-29 address") require.NotNil(t, quicV1Addr, "expected to have a QUIC v1 address") ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) @@ -165,36 +71,14 @@ func TestQUICAndWebTransport(t *testing.T) { } h2.Close() - // then test that we can dial a QUIC draft-29 - h3, err := libp2p.New( - libp2p.Transport(libp2pquic.NewTransport), - libp2p.NoListenAddrs, - ) - require.NoError(t, err) - require.NoError(t, h3.Connect(ctx, peer.AddrInfo{ - ID: h1.ID(), - // a libp2p host will prefer dialing v1 if it supports both versions, - // so we need to filter the addresses so it thinks that h1 only supports draft-29 - Addrs: ma.FilterAddrs(h1.Addrs(), func(addr ma.Multiaddr) bool { _, err := addr.ValueForProtocol(ma.P_QUIC); return err == nil }), - })) - for _, conns := range [][]network.Conn{h3.Network().ConnsToPeer(h1.ID()), h1.Network().ConnsToPeer(h3.ID())} { - require.Len(t, conns, 1) - if _, err := conns[0].LocalMultiaddr().ValueForProtocol(ma.P_WEBTRANSPORT); err == nil { - t.Fatalf("expected a QUIC connection, got a WebTransport connection (%s <-> %s)", conns[0].LocalMultiaddr(), conns[0].RemoteMultiaddr()) - } - require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) - require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) - } - h3.Close() - // finally, test that we can dial a WebTransport connection - h4, err := libp2p.New( + h3, err := libp2p.New( libp2p.Transport(webtransport.New), libp2p.NoListenAddrs, ) require.NoError(t, err) - require.NoError(t, h4.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()})) - for _, conns := range [][]network.Conn{h4.Network().ConnsToPeer(h1.ID()), h1.Network().ConnsToPeer(h4.ID())} { + require.NoError(t, h3.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()})) + for _, conns := range [][]network.Conn{h3.Network().ConnsToPeer(h1.ID()), h1.Network().ConnsToPeer(h3.ID())} { require.Len(t, conns, 1) if _, err := conns[0].LocalMultiaddr().ValueForProtocol(ma.P_WEBTRANSPORT); err != nil { t.Fatalf("expected a WebTransport connection, got a QUIC connection (%s <-> %s)", conns[0].LocalMultiaddr(), conns[0].RemoteMultiaddr()) @@ -202,5 +86,5 @@ func TestQUICAndWebTransport(t *testing.T) { require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) } - h4.Close() + h3.Close() } diff --git a/go-libp2p/p2p/test/security/bench_test.go b/go-libp2p/p2p/test/security/bench_test.go new file mode 100644 index 0000000..fb50e3f --- /dev/null +++ b/go-libp2p/p2p/test/security/bench_test.go @@ -0,0 +1,130 @@ +package benchmark + +import ( + "context" + crand "crypto/rand" + "io" + "net" + "sync" + "testing" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/sec" + "github.com/libp2p/go-libp2p/p2p/security/noise" + tls "github.com/libp2p/go-libp2p/p2p/security/tls" + "github.com/stretchr/testify/assert" +) + +type Factory func(*testing.B, crypto.PrivKey) sec.SecureTransport + +func benchmarkThroughput(b *testing.B, size int, factory Factory) { + privA, pubA, err := crypto.GenerateEd25519Key(crand.Reader) + assert.NoError(b, err) + idA, err := peer.IDFromPublicKey(pubA) + assert.NoError(b, err) + tptA := factory(b, privA) + + privB, pubB, err := crypto.GenerateEd25519Key(crand.Reader) + assert.NoError(b, err) + idB, err := peer.IDFromPublicKey(pubB) + assert.NoError(b, err) + tptB := factory(b, privB) + + // pipe here serialize the decryption and encryption, we might want both parallelised to reduce context switching impact on the benchmark. + // https://github.com/golang/go/issues/34502 would be ideal for the parallel usecase. + p1, p2 := net.Pipe() + var ready sync.Mutex // wait for completed handshake + var finished sync.Mutex // wait until all data has been received + ready.Lock() + finished.Lock() + go func() { + defer finished.Unlock() + conn, err := tptB.SecureInbound(context.Background(), p2, idA) + assert.NoError(b, err) + ready.Unlock() + + _, err = io.Copy(io.Discard, conn) + assert.NoError(b, err) + }() + + conn, err := tptA.SecureOutbound(context.Background(), p1, idB) + assert.NoError(b, err) + ready.Lock() + + buf := make([]byte, size) + b.SetBytes(int64(len(buf))) + b.ResetTimer() + + for i := b.N; i != 0; i-- { + _, err = conn.Write(buf[:]) + assert.NoError(b, err) + } + conn.Close() + + finished.Lock() +} +func benchmarkHandshakes(b *testing.B, factory Factory) { + privA, pubA, err := crypto.GenerateEd25519Key(crand.Reader) + assert.NoError(b, err) + idA, err := peer.IDFromPublicKey(pubA) + assert.NoError(b, err) + tptA := factory(b, privA) + + privB, pubB, err := crypto.GenerateEd25519Key(crand.Reader) + assert.NoError(b, err) + idB, err := peer.IDFromPublicKey(pubB) + assert.NoError(b, err) + tptB := factory(b, privB) + + pipes := make(chan net.Conn, 1) + + var finished sync.Mutex // wait until all data has been transferred + finished.Lock() + go func() { + defer finished.Unlock() + var throwAway [1]byte + for p := range pipes { + conn, err := tptB.SecureInbound(context.Background(), p, idA) + assert.NoError(b, err) + _, err = conn.Read(throwAway[:]) // read because currently the tls transport handshake when calling Read. + assert.ErrorIs(b, err, io.EOF) + } + }() + b.ResetTimer() + + for i := b.N; i != 0; i-- { + p1, p2 := net.Pipe() + pipes <- p2 + conn, err := tptA.SecureOutbound(context.Background(), p1, idB) + assert.NoError(b, err) + assert.NoError(b, conn.Close()) + } + close(pipes) + + finished.Lock() +} + +func bench(b *testing.B, factory Factory) { + b.Run("throughput", func(b *testing.B) { + b.Run("32KiB", func(b *testing.B) { benchmarkThroughput(b, 32*1024, factory) }) + b.Run("1MiB", func(b *testing.B) { benchmarkThroughput(b, 1024*1024, factory) }) + }) + b.Run("handshakes", func(b *testing.B) { benchmarkHandshakes(b, factory) }) +} + +func BenchmarkNoise(b *testing.B) { + bench(b, func(b *testing.B, priv crypto.PrivKey) sec.SecureTransport { + tpt, err := noise.New("", priv, nil) + assert.NoError(b, err) + return tpt + }) +} + +func BenchmarkTLS(b *testing.B) { + bench(b, func(b *testing.B, priv crypto.PrivKey) sec.SecureTransport { + tpt, err := tls.New("", priv, nil) + assert.NoError(b, err) + return tpt + }) +} diff --git a/go-libp2p/p2p/test/swarm/swarm_test.go b/go-libp2p/p2p/test/swarm/swarm_test.go new file mode 100644 index 0000000..10298f5 --- /dev/null +++ b/go-libp2p/p2p/test/swarm/swarm_test.go @@ -0,0 +1,245 @@ +package swarm_test + +import ( + "context" + "io" + "sync" + "testing" + "time" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" + "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" + "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDialPeerTransientConnection(t *testing.T) { + h1, err := libp2p.New( + libp2p.NoListenAddrs, + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + h2, err := libp2p.New( + libp2p.NoListenAddrs, + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + relay1, err := libp2p.New() + require.NoError(t, err) + + _, err = relay.New(relay1) + require.NoError(t, err) + + relay1info := peer.AddrInfo{ + ID: relay1.ID(), + Addrs: relay1.Addrs(), + } + err = h1.Connect(context.Background(), relay1info) + require.NoError(t, err) + + err = h2.Connect(context.Background(), relay1info) + require.NoError(t, err) + + _, err = client.Reserve(context.Background(), h2, relay1info) + require.NoError(t, err) + + relayaddr := ma.StringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String()) + + h1.Peerstore().AddAddr(h2.ID(), relayaddr, peerstore.TempAddrTTL) + + // swarm.DialPeer should connect over transient connections + conn1, err := h1.Network().DialPeer(context.Background(), h2.ID()) + require.NoError(t, err) + require.NotNil(t, conn1) + + // Test that repeated calls return the same connection. + conn2, err := h1.Network().DialPeer(context.Background(), h2.ID()) + require.NoError(t, err) + require.NotNil(t, conn2) + + require.Equal(t, conn1, conn2) + + // swarm.DialPeer should fail if forceDirect is used + ctx := network.WithForceDirectDial(context.Background(), "test") + conn, err := h1.Network().DialPeer(ctx, h2.ID()) + require.Error(t, err) + require.Nil(t, conn) +} + +func TestNewStreamTransientConnection(t *testing.T) { + h1, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + h2, err := libp2p.New( + libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"), + libp2p.EnableRelay(), + ) + require.NoError(t, err) + + relay1, err := libp2p.New() + require.NoError(t, err) + + _, err = relay.New(relay1) + require.NoError(t, err) + + relay1info := peer.AddrInfo{ + ID: relay1.ID(), + Addrs: relay1.Addrs(), + } + err = h1.Connect(context.Background(), relay1info) + require.NoError(t, err) + + err = h2.Connect(context.Background(), relay1info) + require.NoError(t, err) + + _, err = client.Reserve(context.Background(), h2, relay1info) + require.NoError(t, err) + + relayaddr := ma.StringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String()) + + h1.Peerstore().AddAddr(h2.ID(), relayaddr, peerstore.TempAddrTTL) + + // WithAllowLimitedConn should succeed + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + ctx = network.WithAllowLimitedConn(ctx, "test") + s, err := h1.Network().NewStream(ctx, h2.ID()) + require.NoError(t, err) + require.NotNil(t, s) + defer s.Close() + + // Without WithAllowLimitedConn should fail with context deadline exceeded + ctx, cancel = context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + s, err = h1.Network().NewStream(ctx, h2.ID()) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Nil(t, s) + + // Provide h2's direct address to h1. + h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.TempAddrTTL) + // network.NoDial should also fail + ctx, cancel = context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + ctx = network.WithNoDial(ctx, "test") + s, err = h1.Network().NewStream(ctx, h2.ID()) + require.ErrorIs(t, err, context.DeadlineExceeded) + require.Nil(t, s) + + done := make(chan bool, 2) + // NewStream should return a stream if an incoming direct connection is established + go func() { + ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = network.WithNoDial(ctx, "test") + s, err = h1.Network().NewStream(ctx, h2.ID()) + assert.NoError(t, err) + assert.NotNil(t, s) + defer s.Close() + require.Equal(t, network.DirInbound, s.Conn().Stat().Direction) + done <- true + }() + go func() { + // connect h2 to h1 simulating connection reversal + h2.Peerstore().AddAddrs(h1.ID(), h1.Addrs(), peerstore.TempAddrTTL) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + ctx = network.WithForceDirectDial(ctx, "test") + err := h2.Connect(ctx, peer.AddrInfo{ID: h1.ID()}) + assert.NoError(t, err) + done <- true + }() + + <-done + <-done +} + +func TestLimitStreamsWhenHangingHandlers(t *testing.T) { + var partial rcmgr.PartialLimitConfig + const streamLimit = 10 + partial.System.Streams = streamLimit + mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(partial.Build(rcmgr.InfiniteLimits))) + require.NoError(t, err) + + maddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic-v1") + require.NoError(t, err) + + receiver, err := libp2p.New( + libp2p.ResourceManager(mgr), + libp2p.ListenAddrs(maddr), + ) + require.NoError(t, err) + t.Cleanup(func() { receiver.Close() }) + + var wg sync.WaitGroup + wg.Add(1) + + const pid = "/test" + receiver.SetStreamHandler(pid, func(s network.Stream) { + defer s.Close() + s.Write([]byte{42}) + wg.Wait() + }) + + // Open streamLimit streams + success := 0 + // we make a lot of tries because identify and identify push take up a few streams + for i := 0; i < 1000 && success < streamLimit; i++ { + mgr, err = rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.InfiniteLimits)) + require.NoError(t, err) + + sender, err := libp2p.New(libp2p.ResourceManager(mgr)) + require.NoError(t, err) + t.Cleanup(func() { sender.Close() }) + + sender.Peerstore().AddAddrs(receiver.ID(), receiver.Addrs(), peerstore.PermanentAddrTTL) + + s, err := sender.NewStream(context.Background(), receiver.ID(), pid) + if err != nil { + continue + } + + var b [1]byte + _, err = io.ReadFull(s, b[:]) + if err == nil { + success++ + } + sender.Close() + } + require.Equal(t, streamLimit, success) + // We have the maximum number of streams open. Next call should fail. + mgr, err = rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.InfiniteLimits)) + require.NoError(t, err) + + sender, err := libp2p.New(libp2p.ResourceManager(mgr)) + require.NoError(t, err) + t.Cleanup(func() { sender.Close() }) + + sender.Peerstore().AddAddrs(receiver.ID(), receiver.Addrs(), peerstore.PermanentAddrTTL) + + _, err = sender.NewStream(context.Background(), receiver.ID(), pid) + require.Error(t, err) + + // Close the open streams + wg.Done() + + // Next call should succeed + require.Eventually(t, func() bool { + s, err := sender.NewStream(context.Background(), receiver.ID(), pid) + if err == nil { + s.Close() + return true + } + return false + }, 5*time.Second, 100*time.Millisecond) +} diff --git a/go-libp2p/p2p/test/transport/deadline_test.go b/go-libp2p/p2p/test/transport/deadline_test.go new file mode 100644 index 0000000..55fa7a4 --- /dev/null +++ b/go-libp2p/p2p/test/transport/deadline_test.go @@ -0,0 +1,94 @@ +package transport_integration + +import ( + "context" + "net" + "testing" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/stretchr/testify/require" +) + +func TestReadWriteDeadlines(t *testing.T) { + // Send a lot of data so that writes have to flush (can't just buffer it all) + sendBuf := make([]byte, 10<<20) + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + listener := tc.HostGenerator(t, TransportTestCaseOpts{}) + defer listener.Close() + dialer := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer dialer.Close() + + require.NoError(t, dialer.Connect(context.Background(), peer.AddrInfo{ + ID: listener.ID(), + Addrs: listener.Addrs(), + })) + + // This simply stalls + listener.SetStreamHandler("/stall", func(s network.Stream) { + time.Sleep(time.Hour) + s.Close() + }) + + t.Run("ReadDeadline", func(t *testing.T) { + s, err := dialer.NewStream(context.Background(), listener.ID(), "/stall") + require.NoError(t, err) + defer s.Close() + + start := time.Now() + // Set a deadline + s.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) + buf := make([]byte, 1) + _, err = s.Read(buf) + require.Error(t, err) + var nerr net.Error + require.ErrorAs(t, err, &nerr) + require.True(t, nerr.Timeout()) + require.Less(t, time.Since(start), 1*time.Second) + }) + + t.Run("WriteDeadline", func(t *testing.T) { + s, err := dialer.NewStream(context.Background(), listener.ID(), "/stall") + require.NoError(t, err) + defer s.Close() + + // Set a deadline + s.SetWriteDeadline(time.Now().Add(10 * time.Millisecond)) + start := time.Now() + _, err = s.Write(sendBuf) + require.Error(t, err) + require.True(t, err.(net.Error).Timeout()) + require.Less(t, time.Since(start), 1*time.Second) + }) + + // Like the above, but with SetDeadline + t.Run("SetDeadline", func(t *testing.T) { + for _, op := range []string{"Read", "Write"} { + t.Run(op, func(t *testing.T) { + s, err := dialer.NewStream(context.Background(), listener.ID(), "/stall") + require.NoError(t, err) + defer s.Close() + + // Set a deadline + s.SetDeadline(time.Now().Add(10 * time.Millisecond)) + start := time.Now() + + if op == "Read" { + buf := make([]byte, 1) + _, err = s.Read(buf) + } else { + _, err = s.Write(sendBuf) + } + require.Error(t, err) + var nerr net.Error + require.ErrorAs(t, err, &nerr) + require.True(t, nerr.Timeout()) + require.Less(t, time.Since(start), 1*time.Second) + }) + } + }) + }) + } +} diff --git a/go-libp2p/p2p/test/transport/gating_test.go b/go-libp2p/p2p/test/transport/gating_test.go index 426fc90..df53da6 100644 --- a/go-libp2p/p2p/test/transport/gating_test.go +++ b/go-libp2p/p2p/test/transport/gating_test.go @@ -2,6 +2,7 @@ package transport_integration import ( "context" + "strings" "testing" "time" @@ -12,12 +13,12 @@ import ( "github.com/libp2p/go-libp2p-testing/race" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) -//go:generate go run github.com/golang/mock/mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater +//go:generate go run go.uber.org/mock/mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater func stripCertHash(addr ma.Multiaddr) ma.Multiaddr { for { @@ -88,6 +89,8 @@ func TestInterceptSecuredOutgoing(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) + defer h1.Close() + defer h2.Close() require.Len(t, h2.Addrs(), 1) require.Len(t, h2.Addrs(), 1) @@ -97,7 +100,7 @@ func TestInterceptSecuredOutgoing(t *testing.T) { connGater.EXPECT().InterceptPeerDial(h2.ID()).Return(true), connGater.EXPECT().InterceptAddrDial(h2.ID(), gomock.Any()).Return(true), connGater.EXPECT().InterceptSecured(network.DirOutbound, h2.ID(), gomock.Any()).Do(func(_ network.Direction, _ peer.ID, addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport addresses + // remove the certhash component from WebTransport and WebRTC addresses require.Equal(t, stripCertHash(h2.Addrs()[0]).String(), addrs.RemoteMultiaddr().String()) }), ) @@ -120,6 +123,8 @@ func TestInterceptUpgradedOutgoing(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) + defer h1.Close() + defer h2.Close() require.Len(t, h2.Addrs(), 1) require.Len(t, h2.Addrs(), 1) @@ -154,19 +159,35 @@ func TestInterceptAccept(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) + defer h1.Close() + defer h2.Close() require.Len(t, h2.Addrs(), 1) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() // The basic host dials the first connection. - connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) - }) + if strings.Contains(tc.Name, "WebRTC") { + // In WebRTC, retransmissions of the STUN packet might cause us to create multiple connections, + // if the first connection attempt is rejected. + connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { + // remove the certhash component from WebTransport addresses + require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) + }).AnyTimes() + } else { + connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { + // remove the certhash component from WebTransport addresses + require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) + }) + } + h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), time.Hour) _, err := h1.NewStream(ctx, h2.ID(), protocol.TestingID) require.Error(t, err) - require.NotErrorIs(t, err, context.DeadlineExceeded) + if _, err := h2.Addrs()[0].ValueForProtocol(ma.P_WEBRTC_DIRECT); err != nil { + // WebRTC rejects connection attempt before an error can be sent to the client. + // This means that the connection attempt will time out. + require.NotErrorIs(t, err, context.DeadlineExceeded) + } }) } } @@ -183,6 +204,8 @@ func TestInterceptSecuredIncoming(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) + defer h1.Close() + defer h2.Close() require.Len(t, h2.Addrs(), 1) ctx, cancel := context.WithTimeout(context.Background(), time.Second) @@ -214,6 +237,8 @@ func TestInterceptUpgradedIncoming(t *testing.T) { h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) + defer h1.Close() + defer h2.Close() require.Len(t, h2.Addrs(), 1) ctx, cancel := context.WithTimeout(context.Background(), time.Second) diff --git a/go-libp2p/p2p/test/transport/mock_connection_gater_test.go b/go-libp2p/p2p/test/transport/mock_connection_gater_test.go index d6efc8b..d617f72 100644 --- a/go-libp2p/p2p/test/transport/mock_connection_gater_test.go +++ b/go-libp2p/p2p/test/transport/mock_connection_gater_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater) +// +// Generated by this command: +// +// mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater +// // Package transport_integration is a generated GoMock package. package transport_integration @@ -7,11 +12,11 @@ package transport_integration import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" control "github.com/libp2p/go-libp2p/core/control" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" ) // MockConnectionGater is a mock of ConnectionGater interface. @@ -46,7 +51,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool } // InterceptAccept indicates an expected call of InterceptAccept. -func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0) } @@ -60,7 +65,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul } // InterceptAddrDial indicates an expected call of InterceptAddrDial. -func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1) } @@ -74,7 +79,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool { } // InterceptPeerDial indicates an expected call of InterceptPeerDial. -func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0) } @@ -88,7 +93,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer } // InterceptSecured indicates an expected call of InterceptSecured. -func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2) } @@ -103,7 +108,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro } // InterceptUpgraded indicates an expected call of InterceptUpgraded. -func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0) } diff --git a/go-libp2p/p2p/test/transport/rcmgr_test.go b/go-libp2p/p2p/test/transport/rcmgr_test.go index 378d1f9..c19a05d 100644 --- a/go-libp2p/p2p/test/transport/rcmgr_test.go +++ b/go-libp2p/p2p/test/transport/rcmgr_test.go @@ -9,14 +9,15 @@ import ( "testing" "time" - gomock "github.com/golang/mock/gomock" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" mocknetwork "github.com/libp2p/go-libp2p/core/network/mocks" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/protocol/identify" "github.com/libp2p/go-libp2p/p2p/protocol/ping" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) func TestResourceManagerIsUsed(t *testing.T) { @@ -55,7 +56,7 @@ func TestResourceManagerIsUsed(t *testing.T) { } expectFd := true - if strings.Contains(tc.Name, "QUIC") || strings.Contains(tc.Name, "WebTransport") { + if strings.Contains(tc.Name, "QUIC") || strings.Contains(tc.Name, "WebTransport") || strings.Contains(tc.Name, "WebRTC") { expectFd = false } @@ -86,7 +87,11 @@ func TestResourceManagerIsUsed(t *testing.T) { } return nil }) - connScope.EXPECT().Done() + if tc.Name == "WebRTC" { + // webrtc receive buffer is a fix sized buffer allocated up front + connScope.EXPECT().ReserveMemory(gomock.Any(), gomock.Any()) + } + connScope.EXPECT().Done().MinTimes(1) var allStreamsDone sync.WaitGroup diff --git a/go-libp2p/p2p/test/transport/transport_test.go b/go-libp2p/p2p/test/transport/transport_test.go index e960806..e39b72a 100644 --- a/go-libp2p/p2p/test/transport/transport_test.go +++ b/go-libp2p/p2p/test/transport/transport_test.go @@ -9,6 +9,7 @@ import ( "io" "net" "runtime" + "strings" "sync" "sync/atomic" "testing" @@ -20,10 +21,16 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/sec" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" + "github.com/libp2p/go-libp2p/p2p/net/swarm" "github.com/libp2p/go-libp2p/p2p/protocol/ping" "github.com/libp2p/go-libp2p/p2p/security/noise" tls "github.com/libp2p/go-libp2p/p2p/security/tls" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + + "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" ) @@ -130,6 +137,21 @@ var transportsToTest = []TransportTestCase{ return h }, }, + { + Name: "WebRTC", + HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { + libp2pOpts := transformOpts(opts) + libp2pOpts = append(libp2pOpts, libp2p.Transport(libp2pwebrtc.New)) + if opts.NoListen { + libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) + } else { + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/webrtc-direct")) + } + h, err := libp2p.New(libp2pOpts...) + require.NoError(t, err) + return h + }, + }, } func TestPing(t *testing.T) { @@ -225,7 +247,7 @@ func TestLotsOfDataManyStreams(t *testing.T) { // 64k buffer const bufSize = 64 << 10 sendBuf := [bufSize]byte{} - const totalStreams = 512 + const totalStreams = 500 const parallel = 8 // Total sends are > 20MiB require.Greater(t, len(sendBuf)*totalStreams, 20<<20) @@ -357,8 +379,20 @@ func TestMoreStreamsThanOurLimits(t *testing.T) { const streamCount = 1024 for _, tc := range transportsToTest { t.Run(tc.Name, func(t *testing.T) { - listener := tc.HostGenerator(t, TransportTestCaseOpts{}) - dialer := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + if strings.Contains(tc.Name, "WebRTC") { + t.Skip("This test potentially exhausts the uint16 WebRTC stream ID space.") + } + listenerLimits := rcmgr.PartialLimitConfig{ + PeerDefault: rcmgr.ResourceLimits{ + Streams: 32, + StreamsInbound: 16, + StreamsOutbound: 16, + }, + } + r, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(listenerLimits.Build(rcmgr.DefaultLimits.AutoScale()))) + require.NoError(t, err) + listener := tc.HostGenerator(t, TransportTestCaseOpts{ResourceManager: r}) + dialer := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, NoRcmgr: true}) defer listener.Close() defer dialer.Close() @@ -370,101 +404,133 @@ func TestMoreStreamsThanOurLimits(t *testing.T) { var handledStreams atomic.Int32 var sawFirstErr atomic.Bool - semaphore := make(chan struct{}, streamCount) - // Start with a single stream at a time. If that works, we'll increase the number of concurrent streams. - semaphore <- struct{}{} + workQueue := make(chan struct{}, streamCount) + for i := 0; i < streamCount; i++ { + workQueue <- struct{}{} + } + close(workQueue) listener.SetStreamHandler("echo", func(s network.Stream) { + // Wait a bit so that we have more parallel streams open at the same time + time.Sleep(time.Millisecond * 10) io.Copy(s, s) s.Close() }) wg := sync.WaitGroup{} - wg.Add(streamCount) errCh := make(chan error, 1) var completedStreams atomic.Int32 - for i := 0; i < streamCount; i++ { - go func() { - <-semaphore - var didErr bool - defer wg.Done() - defer completedStreams.Add(1) - defer func() { - select { - case semaphore <- struct{}{}: - default: - } - if !didErr && !sawFirstErr.Load() { - // No error! We can add one more stream to our concurrency limit. - select { - case semaphore <- struct{}{}: - default: - } - } - }() - var s network.Stream - var err error - // maxRetries is an arbitrary retry amount if there's any error. - maxRetries := streamCount * 4 - shouldRetry := func(err error) bool { - didErr = true - sawFirstErr.Store(true) - maxRetries-- - if maxRetries == 0 || len(errCh) > 0 { - select { - case errCh <- errors.New("max retries exceeded"): - default: - } - return false - } - return true + const maxWorkerCount = streamCount + workerCount := 4 + + var startWorker func(workerIdx int) + startWorker = func(workerIdx int) { + wg.Add(1) + defer wg.Done() + for { + _, ok := <-workQueue + if !ok { + return } - for { - s, err = dialer.NewStream(context.Background(), listener.ID(), "echo") - if err != nil { - if shouldRetry(err) { + // Inline function so we can use defer + func() { + var didErr bool + defer completedStreams.Add(1) + defer func() { + // Only the first worker adds more workers + if workerIdx == 0 && !didErr && !sawFirstErr.Load() { + nextWorkerCount := workerCount * 2 + if nextWorkerCount < maxWorkerCount { + for i := workerCount; i < nextWorkerCount; i++ { + go startWorker(i) + } + workerCount = nextWorkerCount + } + } + }() + + var s network.Stream + var err error + // maxRetries is an arbitrary retry amount if there's any error. + maxRetries := streamCount * 4 + shouldRetry := func(err error) bool { + didErr = true + sawFirstErr.Store(true) + maxRetries-- + if maxRetries == 0 || len(errCh) > 0 { + select { + case errCh <- errors.New("max retries exceeded"): + default: + } + return false + } + return true + } + + for { + s, err = dialer.NewStream(context.Background(), listener.ID(), "echo") + if err != nil { + if shouldRetry(err) { + time.Sleep(50 * time.Millisecond) + continue + } + t.Logf("opening stream failed: %v", err) + return + } + err = func(s network.Stream) error { + defer s.Close() + err = s.SetDeadline(time.Now().Add(100 * time.Millisecond)) + if err != nil { + return err + } + + _, err = s.Write([]byte("hello")) + if err != nil { + return err + } + + err = s.CloseWrite() + if err != nil { + return err + } + + b, err := io.ReadAll(s) + if err != nil { + return err + } + if !bytes.Equal(b, []byte("hello")) { + return errors.New("received data does not match sent data") + } + handledStreams.Add(1) + + return nil + }(s) + if err != nil && shouldRetry(err) { time.Sleep(50 * time.Millisecond) continue } + return } - err = func(s network.Stream) error { - defer s.Close() - _, err = s.Write([]byte("hello")) - if err != nil { - return err - } - - err = s.CloseWrite() - if err != nil { - return err - } - - b, err := io.ReadAll(s) - if err != nil { - return err - } - if !bytes.Equal(b, []byte("hello")) { - return errors.New("received data does not match sent data") - } - handledStreams.Add(1) - - return nil - }(s) - if err != nil && shouldRetry(err) { - time.Sleep(50 * time.Millisecond) - continue - } - return - } - }() + }() + } } + + // Create any initial parallel workers + for i := 1; i < workerCount; i++ { + go startWorker(i) + } + + // Start the first worker + startWorker(0) + wg.Wait() close(errCh) require.NoError(t, <-errCh) require.Equal(t, streamCount, int(handledStreams.Load())) + require.True(t, sawFirstErr.Load(), "Expected to see an error from the peer") }) } } @@ -552,8 +618,8 @@ func TestStreamReadDeadline(t *testing.T) { _, err = s.Read([]byte{0}) require.Error(t, err) require.Contains(t, err.Error(), "deadline") - nerr, ok := err.(net.Error) - require.True(t, ok, "expected a net.Error") + var nerr net.Error + require.ErrorAs(t, err, &nerr, "expected a net.Error") require.True(t, nerr.Timeout(), "expected net.Error.Timeout() == true") // now test that the stream is still usable s.SetReadDeadline(time.Time{}) @@ -566,3 +632,59 @@ func TestStreamReadDeadline(t *testing.T) { }) } } + +func TestDiscoverPeerIDFromSecurityNegotiation(t *testing.T) { + // extracts the peerID of the dialed peer from the error + extractPeerIDFromError := func(inputErr error) (peer.ID, error) { + var dialErr *swarm.DialError + if !errors.As(inputErr, &dialErr) { + return "", inputErr + } + innerErr := dialErr.DialErrors[0].Cause + + var peerIDMismatchErr sec.ErrPeerIDMismatch + if errors.As(innerErr, &peerIDMismatchErr) { + return peerIDMismatchErr.Actual, nil + } + + return "", inputErr + } + + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + h1 := tc.HostGenerator(t, TransportTestCaseOpts{}) + h2 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer h1.Close() + defer h2.Close() + + // runs a test to verify we can extract the peer ID from a target with just its address + t.Helper() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Use a bogus peer ID so that when we connect to the target we get an error telling + // us the targets real peer ID + bogusPeerId, err := peer.Decode("QmadAdJ3f63JyNs65X7HHzqDwV53ynvCcKtNFvdNaz3nhk") + require.NoError(t, err, "the hard coded bogus peerID is invalid") + + ai := &peer.AddrInfo{ + ID: bogusPeerId, + Addrs: []multiaddr.Multiaddr{h1.Addrs()[0]}, + } + + // Try connecting with the bogus peer ID + err = h2.Connect(ctx, *ai) + require.Error(t, err, "somehow we successfully connected to a bogus peerID!") + + // Extract the actual peer ID from the error + newPeerId, err := extractPeerIDFromError(err) + require.NoError(t, err) + ai.ID = newPeerId + // Make sure the new ID is what we expected + require.Equal(t, h1.ID(), ai.ID) + + // and just to double-check try connecting again to make sure it works + require.NoError(t, h2.Connect(ctx, *ai)) + }) + } +} diff --git a/go-libp2p/p2p/transport/quic/cmd/client/main.go b/go-libp2p/p2p/transport/quic/cmd/client/main.go index f33d65e..5736d89 100644 --- a/go-libp2p/p2p/transport/quic/cmd/client/main.go +++ b/go-libp2p/p2p/transport/quic/cmd/client/main.go @@ -1,20 +1,11 @@ package main import ( - "context" - "crypto/rand" "fmt" - "io" "log" "os" - "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" - - ic "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" - libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" - - ma "github.com/multiformats/go-multiaddr" + cmdlib "github.com/libp2p/go-libp2p/p2p/transport/quic/cmd/lib" ) func main() { @@ -22,57 +13,7 @@ func main() { fmt.Printf("Usage: %s ", os.Args[0]) return } - if err := run(os.Args[1], os.Args[2]); err != nil { + if err := cmdlib.RunClient(os.Args[1], os.Args[2]); err != nil { log.Fatalf(err.Error()) } } - -func run(raddr string, p string) error { - peerID, err := peer.Decode(p) - if err != nil { - return err - } - addr, err := ma.NewMultiaddr(raddr) - if err != nil { - return err - } - priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader) - if err != nil { - return err - } - - reuse, err := quicreuse.NewConnManager([32]byte{}) - if err != nil { - return err - } - t, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) - if err != nil { - return err - } - - log.Printf("Dialing %s\n", addr.String()) - conn, err := t.Dial(context.Background(), addr, peerID) - if err != nil { - return err - } - defer conn.Close() - str, err := conn.OpenStream(context.Background()) - if err != nil { - return err - } - defer str.Close() - const msg = "Hello world!" - log.Printf("Sending: %s\n", msg) - if _, err := str.Write([]byte(msg)); err != nil { - return err - } - if err := str.CloseWrite(); err != nil { - return err - } - data, err := io.ReadAll(str) - if err != nil { - return err - } - log.Printf("Received: %s\n", data) - return nil -} diff --git a/go-libp2p/p2p/transport/quic/cmd/lib/lib.go b/go-libp2p/p2p/transport/quic/cmd/lib/lib.go new file mode 100644 index 0000000..fd2a270 --- /dev/null +++ b/go-libp2p/p2p/transport/quic/cmd/lib/lib.go @@ -0,0 +1,129 @@ +package cmdlib + +import ( + "context" + "crypto/rand" + "fmt" + "io" + "log" + + ic "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + tpt "github.com/libp2p/go-libp2p/core/transport" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" + + ma "github.com/multiformats/go-multiaddr" + "github.com/quic-go/quic-go" +) + +func RunClient(raddr string, p string) error { + peerID, err := peer.Decode(p) + if err != nil { + return err + } + addr, err := ma.NewMultiaddr(raddr) + if err != nil { + return err + } + priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader) + if err != nil { + return err + } + + reuse, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) + if err != nil { + return err + } + t, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) + if err != nil { + return err + } + + log.Printf("Dialing %s\n", addr.String()) + conn, err := t.Dial(context.Background(), addr, peerID) + if err != nil { + return err + } + defer conn.Close() + str, err := conn.OpenStream(context.Background()) + if err != nil { + return err + } + defer str.Close() + const msg = "Hello world!" + log.Printf("Sending: %s\n", msg) + if _, err := str.Write([]byte(msg)); err != nil { + return err + } + if err := str.CloseWrite(); err != nil { + return err + } + data, err := io.ReadAll(str) + if err != nil { + return err + } + log.Printf("Received: %s\n", data) + return nil +} + +func RunServer(port string, location chan peer.AddrInfo) error { + addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/udp/%s/quic-v1", port)) + if err != nil { + return err + } + priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader) + if err != nil { + return err + } + peerID, err := peer.IDFromPrivateKey(priv) + if err != nil { + return err + } + + reuse, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) + if err != nil { + return err + } + t, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) + if err != nil { + return err + } + + ln, err := t.Listen(addr) + if err != nil { + return err + } + fmt.Printf("Listening. Now run: go run cmd/client/main.go %s %s\n", ln.Multiaddr(), peerID) + if location != nil { + location <- peer.AddrInfo{ID: peerID, Addrs: []ma.Multiaddr{ln.Multiaddr()}} + } + for { + conn, err := ln.Accept() + if err != nil { + return err + } + log.Printf("Accepted new connection from %s (%s)\n", conn.RemotePeer(), conn.RemoteMultiaddr()) + go func() { + if err := handleConn(conn); err != nil { + log.Printf("handling conn failed: %s", err.Error()) + } + }() + } +} + +func handleConn(conn tpt.CapableConn) error { + str, err := conn.AcceptStream() + if err != nil { + return err + } + data, err := io.ReadAll(str) + if err != nil { + return err + } + log.Printf("Received: %s\n", data) + if _, err := str.Write(data); err != nil { + return err + } + return str.Close() +} diff --git a/go-libp2p/p2p/transport/quic/cmd/lib/lib_test.go b/go-libp2p/p2p/transport/quic/cmd/lib/lib_test.go new file mode 100644 index 0000000..1058b07 --- /dev/null +++ b/go-libp2p/p2p/transport/quic/cmd/lib/lib_test.go @@ -0,0 +1,30 @@ +package cmdlib + +import ( + "testing" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" +) + +func TestCmd(t *testing.T) { + serverLocation := make(chan peer.AddrInfo) + go RunServer("0", serverLocation) + + l := <-serverLocation + + ip, rest := multiaddr.SplitFirst(l.Addrs[0]) + if ip.Protocol().Code == multiaddr.P_IP4 && ip.Value() == "0.0.0.0" { + // Windows can't dial to 0.0.0.0 so replace with localhost + var err error + ip, err = multiaddr.NewComponent("ip4", "127.0.0.1") + if err != nil { + t.Fatal(err) + } + } + + err := RunClient(multiaddr.Join(ip, rest).String(), l.ID.String()) + if err != nil { + t.Fatal(err) + } +} diff --git a/go-libp2p/p2p/transport/quic/cmd/server/main.go b/go-libp2p/p2p/transport/quic/cmd/server/main.go index e5144f4..ef3f90a 100644 --- a/go-libp2p/p2p/transport/quic/cmd/server/main.go +++ b/go-libp2p/p2p/transport/quic/cmd/server/main.go @@ -1,20 +1,11 @@ package main import ( - "crypto/rand" "fmt" - "io" "log" "os" - "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" - - ic "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" - tpt "github.com/libp2p/go-libp2p/core/transport" - libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" - - ma "github.com/multiformats/go-multiaddr" + cmdlib "github.com/libp2p/go-libp2p/p2p/transport/quic/cmd/lib" ) func main() { @@ -22,65 +13,7 @@ func main() { fmt.Printf("Usage: %s ", os.Args[0]) return } - if err := run(os.Args[1]); err != nil { + if err := cmdlib.RunServer(os.Args[1], nil); err != nil { log.Fatalf(err.Error()) } } - -func run(port string) error { - addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/udp/%s/quic", port)) - if err != nil { - return err - } - priv, _, err := ic.GenerateECDSAKeyPair(rand.Reader) - if err != nil { - return err - } - peerID, err := peer.IDFromPrivateKey(priv) - if err != nil { - return err - } - - reuse, err := quicreuse.NewConnManager([32]byte{}) - if err != nil { - return err - } - t, err := libp2pquic.NewTransport(priv, reuse, nil, nil, nil) - if err != nil { - return err - } - - ln, err := t.Listen(addr) - if err != nil { - return err - } - fmt.Printf("Listening. Now run: go run cmd/client/main.go %s %s\n", ln.Multiaddr(), peerID) - for { - conn, err := ln.Accept() - if err != nil { - return err - } - log.Printf("Accepted new connection from %s (%s)\n", conn.RemotePeer(), conn.RemoteMultiaddr()) - go func() { - if err := handleConn(conn); err != nil { - log.Printf("handling conn failed: %s", err.Error()) - } - }() - } -} - -func handleConn(conn tpt.CapableConn) error { - str, err := conn.AcceptStream() - if err != nil { - return err - } - data, err := io.ReadAll(str) - if err != nil { - return err - } - log.Printf("Received: %s\n", data) - if _, err := str.Write(data); err != nil { - return err - } - return str.Close() -} diff --git a/go-libp2p/p2p/transport/quic/conn_test.go b/go-libp2p/p2p/transport/quic/conn_test.go index 189a38d..d3e27a7 100644 --- a/go-libp2p/p2p/transport/quic/conn_test.go +++ b/go-libp2p/p2p/transport/quic/conn_test.go @@ -20,14 +20,14 @@ import ( tpt "github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" "github.com/quic-go/quic-go" quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) -//go:generate sh -c "go run github.com/golang/mock/mockgen -package libp2pquic -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater && go run golang.org/x/tools/cmd/goimports -w mock_connection_gater_test.go" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package libp2pquic -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater && go run golang.org/x/tools/cmd/goimports -w mock_connection_gater_test.go" type connTestCase struct { Name string @@ -35,8 +35,8 @@ type connTestCase struct { } var connTestCases = []*connTestCase{ - {"reuseport_on", []quicreuse.Option{quicreuse.DisableDraft29()}}, - {"reuseport_off", []quicreuse.Option{quicreuse.DisableReuseport(), quicreuse.DisableDraft29()}}, + {"reuseport_on", []quicreuse.Option{}}, + {"reuseport_off", []quicreuse.Option{quicreuse.DisableReuseport()}}, } func createPeer(t *testing.T) (peer.ID, ic.PrivKey) { @@ -55,7 +55,7 @@ func createPeer(t *testing.T) (peer.ID, ic.PrivKey) { require.NoError(t, err) id, err := peer.IDFromPrivateKey(priv) require.NoError(t, err) - t.Logf("using a %s key: %s", priv.Type(), id.Pretty()) + t.Logf("using a %s key: %s", priv.Type(), id) return id, priv } @@ -69,7 +69,7 @@ func runServer(t *testing.T, tr tpt.Transport, addr string) tpt.Listener { func newConnManager(t *testing.T, opts ...quicreuse.Option) *quicreuse.ConnManager { t.Helper() - cm, err := quicreuse.NewConnManager([32]byte{}, opts...) + cm, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, opts...) require.NoError(t, err) t.Cleanup(func() { cm.Close() }) return cm @@ -674,110 +674,3 @@ func TestHolePunching(t *testing.T) { <-done1 <-done2 } - -func TestGetErrorWhenListeningWithDraft29WhenDisabled(t *testing.T) { - _, serverKey := createPeer(t) - - t1, err := NewTransport(serverKey, newConnManager(t, quicreuse.DisableDraft29()), nil, nil, nil) - require.NoError(t, err) - defer t1.(io.Closer).Close() - laddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic") - require.NoError(t, err) - _, err = t1.Listen(laddr) - require.Error(t, err) -} - -func TestClientCanDialDifferentQUICVersions(t *testing.T) { - type testCase struct { - name string - serverDisablesDraft29 bool - } - - testCases := []testCase{ - { - name: "Client dials quic-v1 on a quic-v1 only server", - serverDisablesDraft29: true, - }, - { - name: "Client dials both draft 29 and v1 on server that supports both", - serverDisablesDraft29: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - serverID, serverKey := createPeer(t) - _, clientKey := createPeer(t) - - var serverOpts []quicreuse.Option - if tc.serverDisablesDraft29 { - serverOpts = append(serverOpts, quicreuse.DisableDraft29()) - } - - t1, err := NewTransport(serverKey, newConnManager(t, serverOpts...), nil, nil, nil) - require.NoError(t, err) - defer t1.(io.Closer).Close() - laddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") - ln1, err := t1.Listen(laddr) - require.NoError(t, err) - t.Cleanup(func() { ln1.Close() }) - - mas := []ma.Multiaddr{ln1.Multiaddr()} - var ln2 tpt.Listener - if !tc.serverDisablesDraft29 { - laddrDraft29 := ma.StringCast("/ip4/127.0.0.1/udp/0/quic") - ln2, err = t1.Listen(laddrDraft29) - require.NoError(t, err) - t.Cleanup(func() { ln2.Close() }) - mas = append(mas, ln2.Multiaddr()) - } - - t2, err := NewTransport(clientKey, newConnManager(t), nil, nil, nil) - require.NoError(t, err) - defer t2.(io.Closer).Close() - - ctx := context.Background() - - for _, a := range mas { - _, v, err := quicreuse.FromQuicMultiaddr(a) - require.NoError(t, err) - - done := make(chan struct{}) - go func() { - defer close(done) - var conn tpt.CapableConn - var err error - if v == quic.Version1 { - conn, err = ln1.Accept() - } else if v == quic.VersionDraft29 { - conn, err = ln2.Accept() - } else { - panic("unexpected version") - } - require.NoError(t, err) - - _, versionConnLocal, err := quicreuse.FromQuicMultiaddr(conn.LocalMultiaddr()) - require.NoError(t, err) - _, versionConnRemote, err := quicreuse.FromQuicMultiaddr(conn.RemoteMultiaddr()) - require.NoError(t, err) - - require.Equal(t, v, versionConnLocal) - require.Equal(t, v, versionConnRemote) - }() - - conn, err := t2.Dial(ctx, a, serverID) - require.NoError(t, err) - _, versionConnLocal, err := quicreuse.FromQuicMultiaddr(conn.LocalMultiaddr()) - require.NoError(t, err) - _, versionConnRemote, err := quicreuse.FromQuicMultiaddr(conn.RemoteMultiaddr()) - require.NoError(t, err) - - require.Equal(t, v, versionConnLocal) - require.Equal(t, v, versionConnRemote) - - <-done - conn.Close() - } - }) - } -} diff --git a/go-libp2p/p2p/transport/quic/listener.go b/go-libp2p/p2p/transport/quic/listener.go index 73bb502..d49b686 100644 --- a/go-libp2p/p2p/transport/quic/listener.go +++ b/go-libp2p/p2p/transport/quic/listener.go @@ -29,9 +29,6 @@ type listener struct { func newListener(ln quicreuse.Listener, t *transport, localPeer peer.ID, key ic.PrivKey, rcmgr network.ResourceManager) (listener, error) { localMultiaddrs := make(map[quic.VersionNumber]ma.Multiaddr) for _, addr := range ln.Multiaddrs() { - if _, err := addr.ValueForProtocol(ma.P_QUIC); err == nil { - localMultiaddrs[quic.VersionDraft29] = addr - } if _, err := addr.ValueForProtocol(ma.P_QUIC_V1); err == nil { localMultiaddrs[quic.Version1] = addr } diff --git a/go-libp2p/p2p/transport/quic/listener_test.go b/go-libp2p/p2p/transport/quic/listener_test.go index f62cddc..d739c82 100644 --- a/go-libp2p/p2p/transport/quic/listener_test.go +++ b/go-libp2p/p2p/transport/quic/listener_test.go @@ -34,41 +34,31 @@ func TestListenAddr(t *testing.T) { defer tr.(io.Closer).Close() t.Run("for IPv4", func(t *testing.T) { - localAddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic") - ln, err := tr.Listen(localAddr) - require.NoError(t, err) localAddrV1 := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") - ln2, err := tr.Listen(localAddrV1) + ln, err := tr.Listen(localAddrV1) require.NoError(t, err) defer ln.Close() - defer ln2.Close() port := ln.Addr().(*net.UDPAddr).Port require.NotZero(t, port) var multiaddrsStrings []string - for _, a := range []ma.Multiaddr{ln.Multiaddr(), ln2.Multiaddr()} { + for _, a := range []ma.Multiaddr{ln.Multiaddr()} { multiaddrsStrings = append(multiaddrsStrings, a.String()) } - require.Contains(t, multiaddrsStrings, fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic", port)) require.Contains(t, multiaddrsStrings, fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic-v1", port)) }) t.Run("for IPv6", func(t *testing.T) { - localAddr := ma.StringCast("/ip6/::/udp/0/quic") - ln, err := tr.Listen(localAddr) - require.NoError(t, err) localAddrV1 := ma.StringCast("/ip6/::/udp/0/quic-v1") - ln2, err := tr.Listen(localAddrV1) + ln, err := tr.Listen(localAddrV1) require.NoError(t, err) defer ln.Close() - defer ln2.Close() port := ln.Addr().(*net.UDPAddr).Port require.NotZero(t, port) var multiaddrsStrings []string - for _, a := range []ma.Multiaddr{ln.Multiaddr(), ln2.Multiaddr()} { + for _, a := range []ma.Multiaddr{ln.Multiaddr()} { multiaddrsStrings = append(multiaddrsStrings, a.String()) } - require.Contains(t, multiaddrsStrings, fmt.Sprintf("/ip6/::/udp/%d/quic", port)) require.Contains(t, multiaddrsStrings, fmt.Sprintf("/ip6/::/udp/%d/quic-v1", port)) }) } @@ -76,7 +66,7 @@ func TestListenAddr(t *testing.T) { func TestAccepting(t *testing.T) { tr := newTransport(t, nil) defer tr.(io.Closer).Close() - ln, err := tr.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")) + ln, err := tr.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")) require.NoError(t, err) done := make(chan struct{}) go func() { @@ -100,7 +90,7 @@ func TestAccepting(t *testing.T) { func TestAcceptAfterClose(t *testing.T) { tr := newTransport(t, nil) defer tr.(io.Closer).Close() - ln, err := tr.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic")) + ln, err := tr.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1")) require.NoError(t, err) require.NoError(t, ln.Close()) _, err = ln.Accept() @@ -112,23 +102,14 @@ func TestCorrectNumberOfVirtualListeners(t *testing.T) { tpt := tr.(*transport) defer tr.(io.Closer).Close() - localAddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic") - udpAddr, _, err := quicreuse.FromQuicMultiaddr(localAddr) - require.NoError(t, err) - - ln, err := tr.Listen(localAddr) - require.NoError(t, err) - require.Equal(t, 1, len(tpt.listeners[udpAddr.String()])) localAddrV1 := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") - ln2, err := tr.Listen(localAddrV1) + ln, err := tr.Listen(localAddrV1) + require.NoError(t, err) + udpAddr, _, err := quicreuse.FromQuicMultiaddr(localAddrV1) require.NoError(t, err) require.NoError(t, err) - require.Equal(t, 2, len(tpt.listeners[udpAddr.String()])) - + require.Len(t, tpt.listeners[udpAddr.String()], 1) ln.Close() - require.Equal(t, 1, len(tpt.listeners[udpAddr.String()])) - ln2.Close() - require.Equal(t, 0, len(tpt.listeners[udpAddr.String()])) - + require.Empty(t, tpt.listeners[udpAddr.String()]) } diff --git a/go-libp2p/p2p/transport/quic/mock_connection_gater_test.go b/go-libp2p/p2p/transport/quic/mock_connection_gater_test.go index 4ee4008..8e23aad 100644 --- a/go-libp2p/p2p/transport/quic/mock_connection_gater_test.go +++ b/go-libp2p/p2p/transport/quic/mock_connection_gater_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater) +// +// Generated by this command: +// +// mockgen -package libp2pquic -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater +// // Package libp2pquic is a generated GoMock package. package libp2pquic @@ -7,11 +12,11 @@ package libp2pquic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" control "github.com/libp2p/go-libp2p/core/control" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" ) // MockConnectionGater is a mock of ConnectionGater interface. @@ -46,7 +51,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool } // InterceptAccept indicates an expected call of InterceptAccept. -func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0) } @@ -60,7 +65,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul } // InterceptAddrDial indicates an expected call of InterceptAddrDial. -func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1) } @@ -74,7 +79,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool { } // InterceptPeerDial indicates an expected call of InterceptPeerDial. -func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0) } @@ -88,7 +93,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer } // InterceptSecured indicates an expected call of InterceptSecured. -func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2) } @@ -103,7 +108,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro } // InterceptUpgraded indicates an expected call of InterceptUpgraded. -func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0) } diff --git a/go-libp2p/p2p/transport/quic/transport.go b/go-libp2p/p2p/transport/quic/transport.go index aef3f4c..18d198b 100644 --- a/go-libp2p/p2p/transport/quic/transport.go +++ b/go-libp2p/p2p/transport/quic/transport.go @@ -268,8 +268,8 @@ loop: } } -// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic -var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Or(mafmt.Base(ma.P_QUIC), mafmt.Base(ma.P_QUIC_V1))) +// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic-v1 +var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC_V1)) // CanDial determines if we can dial to an address func (t *transport) CanDial(addr ma.Multiaddr) bool { diff --git a/go-libp2p/p2p/transport/quic/transport_test.go b/go-libp2p/p2p/transport/quic/transport_test.go index 3eab828..41e7e4e 100644 --- a/go-libp2p/p2p/transport/quic/transport_test.go +++ b/go-libp2p/p2p/transport/quic/transport_test.go @@ -30,13 +30,10 @@ func TestQUICProtocol(t *testing.T) { defer tr.(io.Closer).Close() protocols := tr.Protocols() - if len(protocols) > 2 { - t.Fatalf("expected at most two protocols, got %v", protocols) + if len(protocols) > 1 { + t.Fatalf("expected at most one protocol, got %v", protocols) } - if protocols[0] != ma.P_QUIC { - t.Fatalf("expected the supported protocol to be draft 29 QUIC, got %d", protocols[0]) - } - if protocols[1] != ma.P_QUIC_V1 { + if protocols[0] != ma.P_QUIC_V1 { t.Fatalf("expected the supported protocol to be QUIC v1, got %d", protocols[0]) } } @@ -48,11 +45,12 @@ func TestCanDial(t *testing.T) { invalid := []string{ "/ip4/127.0.0.1/udp/1234", "/ip4/5.5.5.5/tcp/1234", - "/dns/google.com/udp/443/quic", + "/dns/google.com/udp/443/quic-v1", + "/ip4/127.0.0.1/udp/1234/quic", } valid := []string{ - "/ip4/127.0.0.1/udp/1234/quic", - "/ip4/5.5.5.5/udp/0/quic", + "/ip4/127.0.0.1/udp/1234/quic-v1", + "/ip4/5.5.5.5/udp/0/quic-v1", } for _, s := range invalid { invalidAddr, err := ma.NewMultiaddr(s) diff --git a/go-libp2p/p2p/transport/quicreuse/config.go b/go-libp2p/p2p/transport/quicreuse/config.go index 76a2c8c..92c881e 100644 --- a/go-libp2p/p2p/transport/quicreuse/config.go +++ b/go-libp2p/p2p/transport/quicreuse/config.go @@ -1,7 +1,6 @@ package quicreuse import ( - "net" "time" "github.com/quic-go/quic-go" @@ -12,14 +11,8 @@ var quicConfig = &quic.Config{ MaxIncomingUniStreams: 5, // allow some unidirectional streams, in case we speak WebTransport MaxStreamReceiveWindow: 10 * (1 << 20), // 10 MB MaxConnectionReceiveWindow: 15 * (1 << 20), // 15 MB - RequireAddressValidation: func(net.Addr) bool { - // TODO(#1535): require source address validation when under load - return false - }, - KeepAlivePeriod: 15 * time.Second, - Versions: []quic.VersionNumber{quic.VersionDraft29, quic.Version1}, + KeepAlivePeriod: 15 * time.Second, + Versions: []quic.VersionNumber{quic.Version1}, // We don't use datagrams (yet), but this is necessary for WebTransport EnableDatagrams: true, - // The multiaddress encodes the QUIC version, thus there's no need to send Version Negotiation packets. - DisableVersionNegotiationPackets: true, } diff --git a/go-libp2p/p2p/transport/quicreuse/connmgr.go b/go-libp2p/p2p/transport/quicreuse/connmgr.go index c12b866..ec2b7b2 100644 --- a/go-libp2p/p2p/transport/quicreuse/connmgr.go +++ b/go-libp2p/p2p/transport/quicreuse/connmgr.go @@ -16,7 +16,6 @@ import ( type ConnManager struct { reuseUDP4 *reuse reuseUDP6 *reuse - enableDraft29 bool enableReuseport bool enableMetrics bool @@ -26,8 +25,8 @@ type ConnManager struct { quicListenersMu sync.Mutex quicListeners map[string]quicListenerEntry - srk quic.StatelessResetKey - mt *metricsTracer + srk quic.StatelessResetKey + tokenKey quic.TokenGeneratorKey } type quicListenerEntry struct { @@ -35,12 +34,12 @@ type quicListenerEntry struct { ln *quicListener } -func NewConnManager(statelessResetKey quic.StatelessResetKey, opts ...Option) (*ConnManager, error) { +func NewConnManager(statelessResetKey quic.StatelessResetKey, tokenKey quic.TokenGeneratorKey, opts ...Option) (*ConnManager, error) { cm := &ConnManager{ enableReuseport: true, - enableDraft29: true, quicListeners: make(map[string]quicListenerEntry), srk: statelessResetKey, + tokenKey: tokenKey, } for _, o := range opts { if err := o(cm); err != nil { @@ -50,29 +49,20 @@ func NewConnManager(statelessResetKey quic.StatelessResetKey, opts ...Option) (* quicConf := quicConfig.Clone() - if cm.enableMetrics { - cm.mt = newMetricsTracer() - } - quicConf.Tracer = func(ctx context.Context, p quiclogging.Perspective, ci quic.ConnectionID) quiclogging.ConnectionTracer { - tracers := make([]quiclogging.ConnectionTracer, 0, 2) + quicConf.Tracer = func(ctx context.Context, p quiclogging.Perspective, ci quic.ConnectionID) *quiclogging.ConnectionTracer { + var tracer *quiclogging.ConnectionTracer if qlogTracerDir != "" { - tracers = append(tracers, qloggerForDir(qlogTracerDir, p, ci)) + tracer = qloggerForDir(qlogTracerDir, p, ci) } - if cm.mt != nil { - tracers = append(tracers, cm.mt.TracerForConnection(ctx, p, ci)) - } - return quiclogging.NewMultiplexedConnectionTracer(tracers...) + return tracer } serverConfig := quicConf.Clone() - if !cm.enableDraft29 { - serverConfig.Versions = []quic.VersionNumber{quic.Version1} - } cm.clientConfig = quicConf cm.serverConfig = serverConfig if cm.enableReuseport { - cm.reuseUDP4 = newReuse(&statelessResetKey, cm.mt) - cm.reuseUDP6 = newReuse(&statelessResetKey, cm.mt) + cm.reuseUDP4 = newReuse(&statelessResetKey, &tokenKey) + cm.reuseUDP6 = newReuse(&statelessResetKey, &tokenKey) } return cm, nil } @@ -89,12 +79,6 @@ func (c *ConnManager) getReuse(network string) (*reuse, error) { } func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (Listener, error) { - if !c.enableDraft29 { - if _, err := addr.ValueForProtocol(ma.P_QUIC); err == nil { - return nil, errors.New("can't listen on `/quic` multiaddr (QUIC draft 29 version) when draft 29 support is disabled") - } - } - netw, host, err := manet.DialArgs(addr) if err != nil { return nil, err @@ -114,7 +98,7 @@ func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWi if err != nil { return nil, err } - ln, err := newQuicListener(tr, c.serverConfig, c.enableDraft29) + ln, err := newQuicListener(tr, c.serverConfig) if err != nil { return nil, err } @@ -156,15 +140,18 @@ func (c *ConnManager) transportForListen(network string, laddr *net.UDPAddr) (re return reuse.TransportForListen(network, laddr) } - conn, err := listenAndOptimize(network, laddr) + conn, err := net.ListenUDP(network, laddr) if err != nil { return nil, err } - tr := &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn} - if c.mt != nil { - tr.Transport.Tracer = c.mt - } - return tr, nil + return &singleOwnerTransport{ + packetConn: conn, + Transport: quic.Transport{ + Conn: conn, + StatelessResetKey: &c.srk, + TokenGeneratorKey: &c.tokenKey, + }, + }, nil } func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (quic.Connection, error) { @@ -183,8 +170,6 @@ func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf if v == quic.Version1 { // The endpoint has explicit support for QUIC v1, so we'll only use that version. quicConf.Versions = []quic.VersionNumber{quic.Version1} - } else if v == quic.VersionDraft29 { - quicConf.Versions = []quic.VersionNumber{quic.VersionDraft29} } else { return nil, errors.New("unknown QUIC version") } @@ -217,22 +202,14 @@ func (c *ConnManager) TransportForDial(network string, raddr *net.UDPAddr) (refC case "udp6": laddr = &net.UDPAddr{IP: net.IPv6zero, Port: 0} } - conn, err := listenAndOptimize(network, laddr) + conn, err := net.ListenUDP(network, laddr) if err != nil { return nil, err } - tr := &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn} - if c.mt != nil { - tr.Transport.Tracer = c.mt - } - - return tr, nil + return &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn}, nil } func (c *ConnManager) Protocols() []int { - if c.enableDraft29 { - return []int{ma.P_QUIC, ma.P_QUIC_V1} - } return []int{ma.P_QUIC_V1} } @@ -246,11 +223,6 @@ func (c *ConnManager) Close() error { return c.reuseUDP4.Close() } -// listenAndOptimize same as net.ListenUDP, but also calls quic.OptimizeConn -func listenAndOptimize(network string, laddr *net.UDPAddr) (net.PacketConn, error) { - conn, err := net.ListenUDP(network, laddr) - if err != nil { - return nil, err - } - return quic.OptimizeConn(conn) +func (c *ConnManager) ClientConfig() *quic.Config { + return c.clientConfig } diff --git a/go-libp2p/p2p/transport/quicreuse/connmgr_test.go b/go-libp2p/p2p/transport/quicreuse/connmgr_test.go index 92c7e31..f3576a3 100644 --- a/go-libp2p/p2p/transport/quicreuse/connmgr_test.go +++ b/go-libp2p/p2p/transport/quicreuse/connmgr_test.go @@ -39,18 +39,6 @@ func checkClosed(t *testing.T, cm *ConnManager) { require.Eventually(t, func() bool { return !isGarbageCollectorRunning() }, 200*time.Millisecond, 10*time.Millisecond) } -func TestListenQUICDraft29Disabled(t *testing.T) { - cm, err := NewConnManager([32]byte{}, DisableDraft29(), DisableReuseport()) - require.NoError(t, err) - defer cm.Close() - _, err = cm.ListenQUIC(ma.StringCast("/ip4/127.0.0.1/udp/0/quic"), &tls.Config{}, nil) - require.EqualError(t, err, "can't listen on `/quic` multiaddr (QUIC draft 29 version) when draft 29 support is disabled") - ln, err := cm.ListenQUIC(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"), &tls.Config{NextProtos: []string{"proto"}}, nil) - require.NoError(t, err) - require.NoError(t, ln.Close()) - require.False(t, isGarbageCollectorRunning()) -} - func TestListenOnSameProto(t *testing.T) { t.Run("with reuseport", func(t *testing.T) { testListenOnSameProto(t, true) @@ -66,7 +54,7 @@ func testListenOnSameProto(t *testing.T, enableReuseport bool) { if !enableReuseport { opts = append(opts, DisableReuseport()) } - cm, err := NewConnManager([32]byte{}, opts...) + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, opts...) require.NoError(t, err) defer checkClosed(t, cm) defer cm.Close() @@ -95,7 +83,7 @@ func TestConnectionPassedToQUICForListening(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping on windows. Windows doesn't support these optimizations") } - cm, err := NewConnManager([32]byte{}, DisableReuseport()) + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() @@ -119,7 +107,7 @@ func TestConnectionPassedToQUICForListening(t *testing.T) { func TestAcceptErrorGetCleanedUp(t *testing.T) { raddr := ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1") - cm, err := NewConnManager([32]byte{}, DisableReuseport()) + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() @@ -155,7 +143,7 @@ func TestConnectionPassedToQUICForDialing(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping on windows. Windows doesn't support these optimizations") } - cm, err := NewConnManager([32]byte{}, DisableReuseport()) + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, DisableReuseport()) require.NoError(t, err) defer cm.Close() @@ -230,7 +218,7 @@ func testListener(t *testing.T, enableReuseport bool) { if !enableReuseport { opts = append(opts, DisableReuseport()) } - cm, err := NewConnManager([32]byte{}, opts...) + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, opts...) require.NoError(t, err) id1, tlsConf1 := getTLSConfForProto(t, "proto1") diff --git a/go-libp2p/p2p/transport/quicreuse/listener.go b/go-libp2p/p2p/transport/quicreuse/listener.go index 50b7934..4ee2004 100644 --- a/go-libp2p/p2p/transport/quicreuse/listener.go +++ b/go-libp2p/p2p/transport/quicreuse/listener.go @@ -38,20 +38,13 @@ type quicListener struct { protocols map[string]protoConf } -func newQuicListener(tr refCountedQuicTransport, quicConfig *quic.Config, enableDraft29 bool) (*quicListener, error) { +func newQuicListener(tr refCountedQuicTransport, quicConfig *quic.Config) (*quicListener, error) { localMultiaddrs := make([]ma.Multiaddr, 0, 2) a, err := ToQuicMultiaddr(tr.LocalAddr(), quic.Version1) if err != nil { return nil, err } localMultiaddrs = append(localMultiaddrs, a) - if enableDraft29 { - a, err := ToQuicMultiaddr(tr.LocalAddr(), quic.VersionDraft29) - if err != nil { - return nil, err - } - localMultiaddrs = append(localMultiaddrs, a) - } cl := &quicListener{ protocols: map[string]protoConf{}, running: make(chan struct{}), @@ -59,6 +52,7 @@ func newQuicListener(tr refCountedQuicTransport, quicConfig *quic.Config, enable addrs: localMultiaddrs, } tlsConf := &tls.Config{ + SessionTicketsDisabled: true, // This is set for the config for client, but we set it here as well: https://github.com/quic-go/quic-go/issues/4029 GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) { cl.protocolsMu.Lock() defer cl.protocolsMu.Unlock() @@ -89,7 +83,7 @@ func (l *quicListener) allowWindowIncrease(conn quic.Connection, delta uint64) b l.protocolsMu.Lock() defer l.protocolsMu.Unlock() - conf, ok := l.protocols[conn.ConnectionState().TLS.ConnectionState.NegotiatedProtocol] + conf, ok := l.protocols[conn.ConnectionState().TLS.NegotiatedProtocol] if !ok { return false } diff --git a/go-libp2p/p2p/transport/quicreuse/options.go b/go-libp2p/p2p/transport/quicreuse/options.go index a700a05..c325069 100644 --- a/go-libp2p/p2p/transport/quicreuse/options.go +++ b/go-libp2p/p2p/transport/quicreuse/options.go @@ -9,16 +9,6 @@ func DisableReuseport() Option { } } -// DisableDraft29 disables support for QUIC draft-29. -// This option should be set, unless support for this legacy QUIC version is needed for backwards compatibility. -// Support for QUIC draft-29 is already deprecated and will be removed in the future, see https://github.com/libp2p/go-libp2p/issues/1841. -func DisableDraft29() Option { - return func(m *ConnManager) error { - m.enableDraft29 = false - return nil - } -} - // EnableMetrics enables Prometheus metrics collection. func EnableMetrics() Option { return func(m *ConnManager) error { diff --git a/go-libp2p/p2p/transport/quicreuse/quic_multiaddr.go b/go-libp2p/p2p/transport/quicreuse/quic_multiaddr.go index 12eb7d8..3da4721 100644 --- a/go-libp2p/p2p/transport/quicreuse/quic_multiaddr.go +++ b/go-libp2p/p2p/transport/quicreuse/quic_multiaddr.go @@ -10,8 +10,7 @@ import ( ) var ( - quicV1MA = ma.StringCast("/quic-v1") - quicDraft29MA = ma.StringCast("/quic") + quicV1MA = ma.StringCast("/quic-v1") ) func ToQuicMultiaddr(na net.Addr, version quic.VersionNumber) (ma.Multiaddr, error) { @@ -20,8 +19,6 @@ func ToQuicMultiaddr(na net.Addr, version quic.VersionNumber) (ma.Multiaddr, err return nil, err } switch version { - case quic.VersionDraft29: - return udpMA.Encapsulate(quicDraft29MA), nil case quic.Version1: return udpMA.Encapsulate(quicV1MA), nil default: @@ -34,9 +31,6 @@ func FromQuicMultiaddr(addr ma.Multiaddr) (*net.UDPAddr, quic.VersionNumber, err var partsBeforeQUIC []ma.Multiaddr ma.ForEach(addr, func(c ma.Component) bool { switch c.Protocol().Code { - case ma.P_QUIC: - version = quic.VersionDraft29 - return false case ma.P_QUIC_V1: version = quic.Version1 return false diff --git a/go-libp2p/p2p/transport/quicreuse/quic_multiaddr_test.go b/go-libp2p/p2p/transport/quicreuse/quic_multiaddr_test.go index 23a8b0b..a6242e2 100644 --- a/go-libp2p/p2p/transport/quicreuse/quic_multiaddr_test.go +++ b/go-libp2p/p2p/transport/quicreuse/quic_multiaddr_test.go @@ -11,26 +11,16 @@ import ( func TestConvertToQuicMultiaddr(t *testing.T) { addr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 42), Port: 1337} - maddr, err := ToQuicMultiaddr(addr, quic.VersionDraft29) + maddr, err := ToQuicMultiaddr(addr, quic.Version1) require.NoError(t, err) - require.Equal(t, maddr.String(), "/ip4/192.168.0.42/udp/1337/quic") + require.Equal(t, "/ip4/192.168.0.42/udp/1337/quic-v1", maddr.String()) } func TestConvertToQuicV1Multiaddr(t *testing.T) { addr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 42), Port: 1337} maddr, err := ToQuicMultiaddr(addr, quic.Version1) require.NoError(t, err) - require.Equal(t, maddr.String(), "/ip4/192.168.0.42/udp/1337/quic-v1") -} - -func TestConvertFromQuicDraft29Multiaddr(t *testing.T) { - maddr, err := ma.NewMultiaddr("/ip4/192.168.0.42/udp/1337/quic") - require.NoError(t, err) - udpAddr, v, err := FromQuicMultiaddr(maddr) - require.NoError(t, err) - require.Equal(t, udpAddr.IP, net.IPv4(192, 168, 0, 42)) - require.Equal(t, udpAddr.Port, 1337) - require.Equal(t, v, quic.VersionDraft29) + require.Equal(t, "/ip4/192.168.0.42/udp/1337/quic-v1", maddr.String()) } func TestConvertFromQuicV1Multiaddr(t *testing.T) { @@ -38,7 +28,7 @@ func TestConvertFromQuicV1Multiaddr(t *testing.T) { require.NoError(t, err) udpAddr, v, err := FromQuicMultiaddr(maddr) require.NoError(t, err) - require.Equal(t, udpAddr.IP, net.IPv4(192, 168, 0, 42)) - require.Equal(t, udpAddr.Port, 1337) - require.Equal(t, v, quic.Version1) + require.Equal(t, net.IPv4(192, 168, 0, 42), udpAddr.IP) + require.Equal(t, 1337, udpAddr.Port) + require.Equal(t, quic.Version1, v) } diff --git a/go-libp2p/p2p/transport/quicreuse/reuse.go b/go-libp2p/p2p/transport/quicreuse/reuse.go index 1584b29..dc2b33b 100644 --- a/go-libp2p/p2p/transport/quicreuse/reuse.go +++ b/go-libp2p/p2p/transport/quicreuse/reuse.go @@ -51,8 +51,7 @@ func (c *singleOwnerTransport) Close() error { } func (c *singleOwnerTransport) WriteTo(b []byte, addr net.Addr) (int, error) { - // Safe because we called quic.OptimizeConn ourselves. - return c.packetConn.WriteTo(b, addr) + return c.Transport.WriteTo(b, addr) } // Constant. Defined as variables to simplify testing. @@ -86,8 +85,7 @@ func (c *refcountedTransport) Close() error { } func (c *refcountedTransport) WriteTo(b []byte, addr net.Addr) (int, error) { - // Safe because we called quic.OptimizeConn ourselves. - return c.packetConn.WriteTo(b, addr) + return c.Transport.WriteTo(b, addr) } func (c *refcountedTransport) LocalAddr() net.Addr { @@ -125,10 +123,10 @@ type reuse struct { globalDialers map[int]*refcountedTransport statelessResetKey *quic.StatelessResetKey - metricsTracer *metricsTracer + tokenGeneratorKey *quic.TokenGeneratorKey } -func newReuse(srk *quic.StatelessResetKey, mt *metricsTracer) *reuse { +func newReuse(srk *quic.StatelessResetKey, tokenKey *quic.TokenGeneratorKey) *reuse { r := &reuse{ unicast: make(map[string]map[int]*refcountedTransport), globalListeners: make(map[int]*refcountedTransport), @@ -136,7 +134,7 @@ func newReuse(srk *quic.StatelessResetKey, mt *metricsTracer) *reuse { closeChan: make(chan struct{}), gcStopChan: make(chan struct{}), statelessResetKey: srk, - metricsTracer: mt, + tokenGeneratorKey: tokenKey, } go r.gc() return r @@ -265,17 +263,15 @@ func (r *reuse) transportForDialLocked(network string, source *net.IP) (*refcoun case "udp6": addr = &net.UDPAddr{IP: net.IPv6zero, Port: 0} } - conn, err := listenAndOptimize(network, addr) + conn, err := net.ListenUDP(network, addr) if err != nil { return nil, err } tr := &refcountedTransport{Transport: quic.Transport{ Conn: conn, StatelessResetKey: r.statelessResetKey, + TokenGeneratorKey: r.tokenGeneratorKey, }, packetConn: conn} - if r.metricsTracer != nil { - tr.Transport.Tracer = r.metricsTracer - } r.globalDialers[conn.LocalAddr().(*net.UDPAddr).Port] = tr return tr, nil } @@ -314,19 +310,18 @@ func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcoun } } - conn, err := listenAndOptimize(network, laddr) + conn, err := net.ListenUDP(network, laddr) if err != nil { return nil, err } localAddr := conn.LocalAddr().(*net.UDPAddr) - tr := &refcountedTransport{Transport: quic.Transport{ - Conn: conn, - StatelessResetKey: r.statelessResetKey, - }, packetConn: conn} - if r.metricsTracer != nil { - tr.Transport.Tracer = r.metricsTracer + tr := &refcountedTransport{ + Transport: quic.Transport{ + Conn: conn, + StatelessResetKey: r.statelessResetKey, + }, + packetConn: conn, } - tr.IncreaseCount() // Deal with listen on a global address diff --git a/go-libp2p/p2p/transport/quicreuse/reuse_test.go b/go-libp2p/p2p/transport/quicreuse/reuse_test.go index b373f31..b463094 100644 --- a/go-libp2p/p2p/transport/quicreuse/reuse_test.go +++ b/go-libp2p/p2p/transport/quicreuse/reuse_test.go @@ -69,7 +69,7 @@ func TestReuseListenOnAllIPv4(t *testing.T) { require.NoError(t, err) conn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) - require.Equal(t, conn.GetCount(), 1) + require.Equal(t, 1, conn.GetCount()) } func TestReuseListenOnAllIPv6(t *testing.T) { @@ -82,7 +82,7 @@ func TestReuseListenOnAllIPv6(t *testing.T) { tr, err := reuse.TransportForListen("udp6", addr) require.NoError(t, err) defer tr.Close() - require.Equal(t, tr.GetCount(), 1) + require.Equal(t, 1, tr.GetCount()) } func TestReuseCreateNewGlobalConnOnDial(t *testing.T) { @@ -93,10 +93,10 @@ func TestReuseCreateNewGlobalConnOnDial(t *testing.T) { require.NoError(t, err) conn, err := reuse.TransportForDial("udp4", addr) require.NoError(t, err) - require.Equal(t, conn.GetCount(), 1) + require.Equal(t, 1, conn.GetCount()) laddr := conn.LocalAddr().(*net.UDPAddr) - require.Equal(t, laddr.IP.String(), "0.0.0.0") - require.NotEqual(t, laddr.Port, 0) + require.Equal(t, "0.0.0.0", laddr.IP.String()) + require.NotEqual(t, 0, laddr.Port) } func TestReuseConnectionWhenDialing(t *testing.T) { @@ -107,13 +107,13 @@ func TestReuseConnectionWhenDialing(t *testing.T) { require.NoError(t, err) lconn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) - require.Equal(t, lconn.GetCount(), 1) + require.Equal(t, 1, lconn.GetCount()) // dial raddr, err := net.ResolveUDPAddr("udp4", "1.1.1.1:1234") require.NoError(t, err) conn, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, conn.GetCount(), 2) + require.Equal(t, 2, conn.GetCount()) } func TestReuseConnectionWhenListening(t *testing.T) { @@ -127,8 +127,8 @@ func TestReuseConnectionWhenListening(t *testing.T) { laddr := &net.UDPAddr{IP: net.IPv4zero, Port: tr.LocalAddr().(*net.UDPAddr).Port} lconn, err := reuse.TransportForListen("udp4", laddr) require.NoError(t, err) - require.Equal(t, lconn.GetCount(), 2) - require.Equal(t, tr.GetCount(), 2) + require.Equal(t, 2, lconn.GetCount()) + require.Equal(t, 2, tr.GetCount()) } func TestReuseConnectionWhenDialBeforeListen(t *testing.T) { @@ -151,15 +151,15 @@ func TestReuseConnectionWhenDialBeforeListen(t *testing.T) { require.NoError(t, err) tr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, tr, lTr) - require.Equal(t, tr.GetCount(), 2) + require.Equal(t, lTr, tr) + require.Equal(t, 2, tr.GetCount()) // a listener on an unspecified port should reuse the dialer laddr2 := &net.UDPAddr{IP: net.IPv4zero, Port: 0} lconn2, err := reuse.TransportForListen("udp4", laddr2) require.NoError(t, err) - require.Equal(t, lconn2, rTr) - require.Equal(t, lconn2.GetCount(), 2) + require.Equal(t, rTr, lconn2) + require.Equal(t, 2, lconn2.GetCount()) } func TestReuseListenOnSpecificInterface(t *testing.T) { @@ -181,11 +181,11 @@ func TestReuseListenOnSpecificInterface(t *testing.T) { require.NoError(t, err) lconn, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) - require.Equal(t, lconn.GetCount(), 1) + require.Equal(t, 1, lconn.GetCount()) // dial conn, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, conn.GetCount(), 1) + require.Equal(t, 1, conn.GetCount()) } func TestReuseGarbageCollect(t *testing.T) { @@ -216,13 +216,13 @@ func TestReuseGarbageCollect(t *testing.T) { require.NoError(t, err) dTr, err := reuse.TransportForDial("udp4", raddr) require.NoError(t, err) - require.Equal(t, dTr.GetCount(), 1) + require.Equal(t, 1, dTr.GetCount()) addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:1234") require.NoError(t, err) lTr, err := reuse.TransportForListen("udp4", addr) require.NoError(t, err) - require.Equal(t, lTr.GetCount(), 1) + require.Equal(t, 1, lTr.GetCount()) closeTime := time.Now() lTr.DecreaseCount() @@ -233,7 +233,7 @@ func TestReuseGarbageCollect(t *testing.T) { if closeTime.Add(maxUnusedDuration).Before(time.Now()) { break } - require.Equal(t, num, 2) + require.Equal(t, 2, num) time.Sleep(2 * time.Millisecond) } require.Eventually(t, func() bool { return numGlobals() == 0 }, 4*garbageCollectInterval, 10*time.Millisecond) diff --git a/go-libp2p/p2p/transport/quicreuse/tracer.go b/go-libp2p/p2p/transport/quicreuse/tracer.go index 1386a5c..16c7dce 100644 --- a/go-libp2p/p2p/transport/quicreuse/tracer.go +++ b/go-libp2p/p2p/transport/quicreuse/tracer.go @@ -24,7 +24,7 @@ func init() { qlogTracerDir = os.Getenv("QLOGDIR") } -func qloggerForDir(qlogDir string, p logging.Perspective, ci quic.ConnectionID) logging.ConnectionTracer { +func qloggerForDir(qlogDir string, p logging.Perspective, ci quic.ConnectionID) *logging.ConnectionTracer { // create the QLOGDIR, if it doesn't exist if err := os.MkdirAll(qlogDir, 0777); err != nil { log.Errorf("creating the QLOGDIR failed: %s", err) diff --git a/go-libp2p/p2p/transport/quicreuse/tracer_metrics.go b/go-libp2p/p2p/transport/quicreuse/tracer_metrics.go deleted file mode 100644 index 03e73fd..0000000 --- a/go-libp2p/p2p/transport/quicreuse/tracer_metrics.go +++ /dev/null @@ -1,372 +0,0 @@ -package quicreuse - -import ( - "context" - "errors" - "fmt" - "net" - "sync" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/logging" -) - -var ( - bytesTransferred *prometheus.CounterVec - newConns *prometheus.CounterVec - closedConns *prometheus.CounterVec - sentPackets *prometheus.CounterVec - rcvdPackets *prometheus.CounterVec - bufferedPackets *prometheus.CounterVec - droppedPackets *prometheus.CounterVec - lostPackets *prometheus.CounterVec - connErrors *prometheus.CounterVec -) - -type aggregatingCollector struct { - mutex sync.Mutex - - conns map[string] /* conn ID */ *metricsConnTracer - rtts prometheus.Histogram - connDurations prometheus.Histogram -} - -func newAggregatingCollector() *aggregatingCollector { - return &aggregatingCollector{ - conns: make(map[string]*metricsConnTracer), - rtts: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "quic_smoothed_rtt", - Help: "Smoothed RTT", - Buckets: prometheus.ExponentialBuckets(0.001, 1.25, 40), // 1ms to ~6000ms - }), - connDurations: prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "quic_connection_duration", - Help: "Connection Duration", - Buckets: prometheus.ExponentialBuckets(1, 1.5, 40), // 1s to ~12 weeks - }), - } -} - -var _ prometheus.Collector = &aggregatingCollector{} - -func (c *aggregatingCollector) Describe(descs chan<- *prometheus.Desc) { - descs <- c.rtts.Desc() - descs <- c.connDurations.Desc() -} - -func (c *aggregatingCollector) Collect(metrics chan<- prometheus.Metric) { - now := time.Now() - c.mutex.Lock() - for _, conn := range c.conns { - if rtt, valid := conn.getSmoothedRTT(); valid { - c.rtts.Observe(rtt.Seconds()) - } - c.connDurations.Observe(now.Sub(conn.startTime).Seconds()) - } - c.mutex.Unlock() - metrics <- c.rtts - metrics <- c.connDurations -} - -func (c *aggregatingCollector) AddConn(id string, t *metricsConnTracer) { - c.mutex.Lock() - c.conns[id] = t - c.mutex.Unlock() -} - -func (c *aggregatingCollector) RemoveConn(id string) { - c.mutex.Lock() - delete(c.conns, id) - c.mutex.Unlock() -} - -var collector *aggregatingCollector - -var initMetricsOnce sync.Once - -func initMetrics() { - const ( - direction = "direction" - encLevel = "encryption_level" - ) - - closedConns = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_connections_closed_total", - Help: "closed QUIC connection", - }, - []string{direction}, - ) - prometheus.MustRegister(closedConns) - newConns = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_connections_new_total", - Help: "new QUIC connection", - }, - []string{direction, "handshake_successful"}, - ) - prometheus.MustRegister(newConns) - bytesTransferred = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_transferred_bytes", - Help: "QUIC bytes transferred", - }, - []string{direction}, // TODO: this is confusing. Other times, we use direction for the perspective - ) - prometheus.MustRegister(bytesTransferred) - sentPackets = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_packets_sent_total", - Help: "QUIC packets sent", - }, - []string{encLevel}, - ) - prometheus.MustRegister(sentPackets) - rcvdPackets = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_packets_rcvd_total", - Help: "QUIC packets received", - }, - []string{encLevel}, - ) - prometheus.MustRegister(rcvdPackets) - bufferedPackets = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_packets_buffered_total", - Help: "Buffered packets", - }, - []string{"packet_type"}, - ) - prometheus.MustRegister(bufferedPackets) - droppedPackets = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_packets_dropped_total", - Help: "Dropped packets", - }, - []string{"packet_type", "reason"}, - ) - prometheus.MustRegister(droppedPackets) - connErrors = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_connection_errors_total", - Help: "QUIC connection errors", - }, - []string{"side", "error_code"}, - ) - prometheus.MustRegister(connErrors) - lostPackets = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "quic_packets_lost_total", - Help: "QUIC lost received", - }, - []string{encLevel, "reason"}, - ) - prometheus.MustRegister(lostPackets) - collector = newAggregatingCollector() - prometheus.MustRegister(collector) -} - -type metricsTracer struct { - logging.NullTracer -} - -var _ logging.Tracer = &metricsTracer{} - -func newMetricsTracer() *metricsTracer { - initMetricsOnce.Do(func() { initMetrics() }) - return &metricsTracer{} -} - -func (m *metricsTracer) TracerForConnection(_ context.Context, p logging.Perspective, connID logging.ConnectionID) logging.ConnectionTracer { - return &metricsConnTracer{perspective: p, connID: connID} -} - -func (m *metricsTracer) SentPacket(_ net.Addr, _ *logging.Header, size logging.ByteCount, _ []logging.Frame) { - bytesTransferred.WithLabelValues("sent").Add(float64(size)) -} - -type metricsConnTracer struct { - logging.NullConnectionTracer - - perspective logging.Perspective - startTime time.Time - connID logging.ConnectionID - handshakeComplete bool - - mutex sync.Mutex - numRTTMeasurements int - rtt time.Duration -} - -var _ logging.ConnectionTracer = &metricsConnTracer{} - -func (m *metricsConnTracer) getDirection() string { - if m.perspective == logging.PerspectiveClient { - return "outgoing" - } - return "incoming" -} - -func (m *metricsConnTracer) getEncLevel(packetType logging.PacketType) string { - switch packetType { - case logging.PacketType0RTT: - return "0-RTT" - case logging.PacketTypeInitial: - return "Initial" - case logging.PacketTypeHandshake: - return "Handshake" - case logging.PacketTypeRetry: - return "Retry" - case logging.PacketType1RTT: - return "1-RTT" - default: - return "unknown" - } -} - -func (m *metricsConnTracer) StartedConnection(net.Addr, net.Addr, logging.ConnectionID, logging.ConnectionID) { - m.startTime = time.Now() - collector.AddConn(m.connID.String(), m) -} - -func (m *metricsConnTracer) ClosedConnection(e error) { - var ( - applicationErr *quic.ApplicationError - transportErr *quic.TransportError - statelessResetErr *quic.StatelessResetError - vnErr *quic.VersionNegotiationError - idleTimeoutErr *quic.IdleTimeoutError - handshakeTimeoutErr *quic.HandshakeTimeoutError - remote bool - desc string - ) - - switch { - case errors.As(e, &applicationErr): - return - case errors.As(e, &transportErr): - remote = transportErr.Remote - desc = transportErr.ErrorCode.String() - case errors.As(e, &statelessResetErr): - remote = true - desc = "stateless_reset" - case errors.As(e, &vnErr): - desc = "version_negotiation" - case errors.As(e, &idleTimeoutErr): - desc = "idle_timeout" - case errors.As(e, &handshakeTimeoutErr): - desc = "handshake_timeout" - default: - desc = fmt.Sprintf("unknown error: %v", e) - } - - side := "local" - if remote { - side = "remote" - } - connErrors.WithLabelValues(side, desc).Inc() -} -func (m *metricsConnTracer) SentPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, _ *logging.AckFrame, _ []logging.Frame) { - bytesTransferred.WithLabelValues("sent").Add(float64(size)) - sentPackets.WithLabelValues(m.getEncLevel(logging.PacketTypeFromHeader(&hdr.Header))).Inc() -} - -func (m *metricsConnTracer) ReceivedVersionNegotiationPacket(dst, src logging.ArbitraryLenConnectionID, v []logging.VersionNumber) { - bytesTransferred.WithLabelValues("rcvd").Add(1 /* header form byte */ + 4 /* version number */ + 2 /* src and dest conn id length fields */ + float64(dst.Len()+src.Len()) + float64(4*len(v))) - rcvdPackets.WithLabelValues("Version Negotiation").Inc() -} - -func (m *metricsConnTracer) ReceivedRetry(*logging.Header) { - rcvdPackets.WithLabelValues("Retry").Inc() -} - -func (m *metricsConnTracer) ReceivedPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, _ []logging.Frame) { - bytesTransferred.WithLabelValues("rcvd").Add(float64(size)) - rcvdPackets.WithLabelValues(m.getEncLevel(logging.PacketTypeFromHeader(&hdr.Header))).Inc() -} - -func (m *metricsConnTracer) BufferedPacket(packetType logging.PacketType, _ logging.ByteCount) { - bufferedPackets.WithLabelValues(m.getEncLevel(packetType)).Inc() -} - -func (m *metricsConnTracer) DroppedPacket(packetType logging.PacketType, size logging.ByteCount, r logging.PacketDropReason) { - bytesTransferred.WithLabelValues("rcvd").Add(float64(size)) - var reason string - switch r { - case logging.PacketDropKeyUnavailable: - reason = "key_unavailable" - case logging.PacketDropUnknownConnectionID: - reason = "unknown_connection_id" - case logging.PacketDropHeaderParseError: - reason = "header_parse_error" - case logging.PacketDropPayloadDecryptError: - reason = "payload_decrypt_error" - case logging.PacketDropProtocolViolation: - reason = "protocol_violation" - case logging.PacketDropDOSPrevention: - reason = "dos_prevention" - case logging.PacketDropUnsupportedVersion: - reason = "unsupported_version" - case logging.PacketDropUnexpectedPacket: - reason = "unexpected_packet" - case logging.PacketDropUnexpectedSourceConnectionID: - reason = "unexpected_source_connection_id" - case logging.PacketDropUnexpectedVersion: - reason = "unexpected_version" - case logging.PacketDropDuplicate: - reason = "duplicate" - default: - reason = "unknown" - } - droppedPackets.WithLabelValues(m.getEncLevel(packetType), reason).Inc() -} - -func (m *metricsConnTracer) UpdatedMetrics(rttStats *logging.RTTStats, cwnd, bytesInFlight logging.ByteCount, packetsInFlight int) { - m.mutex.Lock() - m.rtt = rttStats.SmoothedRTT() - m.numRTTMeasurements++ - m.mutex.Unlock() -} - -func (m *metricsConnTracer) LostPacket(level logging.EncryptionLevel, _ logging.PacketNumber, r logging.PacketLossReason) { - var reason string - switch r { - case logging.PacketLossReorderingThreshold: - reason = "reordering_threshold" - case logging.PacketLossTimeThreshold: - reason = "time_threshold" - default: - reason = "unknown" - } - lostPackets.WithLabelValues(level.String(), reason).Inc() -} - -func (m *metricsConnTracer) DroppedEncryptionLevel(level logging.EncryptionLevel) { - if level == logging.EncryptionHandshake { - m.handleHandshakeComplete() - } -} - -func (m *metricsConnTracer) Close() { - if m.handshakeComplete { - closedConns.WithLabelValues(m.getDirection()).Inc() - } else { - newConns.WithLabelValues(m.getDirection(), "false").Inc() - } - collector.RemoveConn(m.connID.String()) -} - -func (m *metricsConnTracer) handleHandshakeComplete() { - m.handshakeComplete = true - newConns.WithLabelValues(m.getDirection(), "true").Inc() -} - -func (m *metricsConnTracer) getSmoothedRTT() (rtt time.Duration, valid bool) { - m.mutex.Lock() - rtt = m.rtt - valid = m.numRTTMeasurements > 10 - m.mutex.Unlock() - return -} diff --git a/go-libp2p/p2p/transport/quicreuse/tracer_test.go b/go-libp2p/p2p/transport/quicreuse/tracer_test.go index 5d1d74f..3347c5f 100644 --- a/go-libp2p/p2p/transport/quicreuse/tracer_test.go +++ b/go-libp2p/p2p/transport/quicreuse/tracer_test.go @@ -33,12 +33,12 @@ func TestSaveQlog(t *testing.T) { qlogDir := createLogDir(t) logger := newQlogger(qlogDir, logging.PerspectiveServer, quic.ConnectionIDFromBytes([]byte{0xde, 0xad, 0xbe, 0xef})) file := getFile(t, qlogDir) - require.Equal(t, string(file.Name()[0]), ".") + require.Equal(t, ".", string(file.Name()[0])) require.Truef(t, strings.HasSuffix(file.Name(), ".qlog.swp"), "expected %s to have the .qlog.swp file ending", file.Name()) // close the logger. This should move the file. require.NoError(t, logger.Close()) file = getFile(t, qlogDir) - require.NotEqual(t, string(file.Name()[0]), ".") + require.NotEqual(t, ".", string(file.Name()[0])) require.Truef(t, strings.HasSuffix(file.Name(), ".qlog.zst"), "expected %s to have the .qlog.zst file ending", file.Name()) require.Contains(t, file.Name(), "server") require.Contains(t, file.Name(), "deadbeef") @@ -66,10 +66,10 @@ func TestQlogCompression(t *testing.T) { require.NoError(t, logger.Close()) compressed, err := os.ReadFile(qlogDir + "/" + getFile(t, qlogDir).Name()) require.NoError(t, err) - require.NotEqual(t, compressed, "foobar") + require.NotEqual(t, "foobar", compressed) c, err := zstd.NewReader(bytes.NewReader(compressed)) require.NoError(t, err) data, err := io.ReadAll(c) require.NoError(t, err) - require.Equal(t, data, []byte("foobar")) + require.Equal(t, []byte("foobar"), data) } diff --git a/go-libp2p/p2p/transport/tcp/metrics.go b/go-libp2p/p2p/transport/tcp/metrics.go index fc2add4..4434b03 100644 --- a/go-libp2p/p2p/transport/tcp/metrics.go +++ b/go-libp2p/p2p/transport/tcp/metrics.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build !windows && !riscv64 && !loong64 package tcp diff --git a/go-libp2p/p2p/transport/tcp/metrics_general.go b/go-libp2p/p2p/transport/tcp/metrics_general.go index 6b67283..419fff3 100644 --- a/go-libp2p/p2p/transport/tcp/metrics_general.go +++ b/go-libp2p/p2p/transport/tcp/metrics_general.go @@ -1,4 +1,4 @@ -//go:build !linux && !darwin && !windows +//go:build !linux && !darwin && !windows && !riscv64 && !loong64 package tcp diff --git a/go-libp2p/p2p/transport/tcp/metrics_windows.go b/go-libp2p/p2p/transport/tcp/metrics_none.go similarity index 68% rename from go-libp2p/p2p/transport/tcp/metrics_windows.go rename to go-libp2p/p2p/transport/tcp/metrics_none.go index 7142e7d..8538b30 100644 --- a/go-libp2p/p2p/transport/tcp/metrics_windows.go +++ b/go-libp2p/p2p/transport/tcp/metrics_none.go @@ -1,4 +1,6 @@ -//go:build windows +// riscv64 see: https://github.com/marten-seemann/tcp/pull/1 + +//go:build windows || riscv64 || loong64 package tcp diff --git a/go-libp2p/p2p/transport/tcp/tcp.go b/go-libp2p/p2p/transport/tcp/tcp.go index f277b3f..d52bb96 100644 --- a/go-libp2p/p2p/transport/tcp/tcp.go +++ b/go-libp2p/p2p/transport/tcp/tcp.go @@ -131,6 +131,7 @@ type TcpTransport struct { } var _ transport.Transport = &TcpTransport{} +var _ transport.DialUpdater = &TcpTransport{} // NewTCPTransport creates a tcp transport object that tracks dialers and listeners // created. It represents an entire TCP stack (though it might not necessarily be). @@ -176,13 +177,17 @@ func (t *TcpTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (manet.Co // Dial dials the peer at the remote address. func (t *TcpTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { + return t.DialWithUpdates(ctx, raddr, p, nil) +} + +func (t *TcpTransport) DialWithUpdates(ctx context.Context, raddr ma.Multiaddr, p peer.ID, updateChan chan<- transport.DialUpdate) (transport.CapableConn, error) { connScope, err := t.rcmgr.OpenConnection(network.DirOutbound, true, raddr) if err != nil { log.Debugw("resource manager blocked outgoing connection", "peer", p, "addr", raddr, "error", err) return nil, err } - c, err := t.dialWithScope(ctx, raddr, p, connScope) + c, err := t.dialWithScope(ctx, raddr, p, connScope, updateChan) if err != nil { connScope.Done() return nil, err @@ -190,7 +195,7 @@ func (t *TcpTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) return c, nil } -func (t *TcpTransport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p peer.ID, connScope network.ConnManagementScope) (transport.CapableConn, error) { +func (t *TcpTransport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p peer.ID, connScope network.ConnManagementScope, updateChan chan<- transport.DialUpdate) (transport.CapableConn, error) { if err := connScope.SetPeer(p); err != nil { log.Debugw("resource manager blocked outgoing connection for peer", "peer", p, "addr", raddr, "error", err) return nil, err @@ -212,6 +217,13 @@ func (t *TcpTransport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p return nil, err } } + if updateChan != nil { + select { + case updateChan <- transport.DialUpdate{Kind: transport.UpdateKindHandshakeProgressed, Addr: raddr}: + default: + // It is better to skip the update than to delay upgrading the connection + } + } direction := network.DirOutbound if ok, isClient, _ := network.GetSimultaneousConnect(ctx); ok && !isClient { direction = network.DirInbound diff --git a/go-libp2p/p2p/transport/tcp/tcp_test.go b/go-libp2p/p2p/transport/tcp/tcp_test.go index 05b6cb9..a57a65e 100644 --- a/go-libp2p/p2p/transport/tcp/tcp_test.go +++ b/go-libp2p/p2p/transport/tcp/tcp_test.go @@ -16,9 +16,10 @@ import ( tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader" ttransport "github.com/libp2p/go-libp2p/p2p/transport/testsuite" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) var muxers = []tptu.StreamMuxer{{ID: "/yamux", Muxer: yamux.DefaultTransport}} @@ -147,6 +148,54 @@ func TestTcpTransportCantListenUtp(t *testing.T) { envReuseportVal = true } +func TestDialWithUpdates(t *testing.T) { + peerA, ia := makeInsecureMuxer(t) + _, ib := makeInsecureMuxer(t) + + ua, err := tptu.New(ia, muxers, nil, nil, nil) + require.NoError(t, err) + ta, err := NewTCPTransport(ua, nil) + require.NoError(t, err) + ln, err := ta.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + require.NoError(t, err) + defer ln.Close() + + ub, err := tptu.New(ib, muxers, nil, nil, nil) + require.NoError(t, err) + tb, err := NewTCPTransport(ub, nil) + require.NoError(t, err) + + updCh := make(chan transport.DialUpdate, 1) + conn, err := tb.DialWithUpdates(context.Background(), ln.Multiaddr(), peerA, updCh) + upd := <-updCh + require.Equal(t, transport.UpdateKindHandshakeProgressed, upd.Kind) + require.NotNil(t, conn) + require.NoError(t, err) + + acceptAndClose := func() manet.Listener { + li, err := manet.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + if err != nil { + t.Fatal(err) + } + go func() { + conn, err := li.Accept() + if err != nil { + return + } + conn.Close() + }() + return li + } + li := acceptAndClose() + defer li.Close() + // This dial will fail as acceptAndClose will not upgrade the connection + conn, err = tb.DialWithUpdates(context.Background(), li.Multiaddr(), peerA, updCh) + upd = <-updCh + require.Equal(t, transport.UpdateKindHandshakeProgressed, upd.Kind) + require.Nil(t, conn) + require.Error(t, err) +} + func makeInsecureMuxer(t *testing.T) (peer.ID, []sec.SecureTransport) { t.Helper() priv, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 256) diff --git a/go-libp2p/p2p/transport/webrtc/connection.go b/go-libp2p/p2p/transport/webrtc/connection.go new file mode 100644 index 0000000..cd28ec3 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/connection.go @@ -0,0 +1,255 @@ +package libp2pwebrtc + +import ( + "context" + "errors" + "fmt" + "math" + "net" + "sync" + "sync/atomic" + + ic "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + tpt "github.com/libp2p/go-libp2p/core/transport" + + ma "github.com/multiformats/go-multiaddr" + "github.com/pion/datachannel" + "github.com/pion/webrtc/v3" +) + +var _ tpt.CapableConn = &connection{} + +const maxAcceptQueueLen = 256 + +type errConnectionTimeout struct{} + +var _ net.Error = &errConnectionTimeout{} + +func (errConnectionTimeout) Error() string { return "connection timeout" } +func (errConnectionTimeout) Timeout() bool { return true } +func (errConnectionTimeout) Temporary() bool { return false } + +type dataChannel struct { + stream datachannel.ReadWriteCloser + channel *webrtc.DataChannel +} + +type connection struct { + pc *webrtc.PeerConnection + transport *WebRTCTransport + scope network.ConnManagementScope + + closeOnce sync.Once + closeErr error + + localPeer peer.ID + localMultiaddr ma.Multiaddr + + remotePeer peer.ID + remoteKey ic.PubKey + remoteMultiaddr ma.Multiaddr + + m sync.Mutex + streams map[uint16]*stream + nextStreamID atomic.Int32 + + acceptQueue chan dataChannel + + ctx context.Context + cancel context.CancelFunc +} + +func newConnection( + direction network.Direction, + pc *webrtc.PeerConnection, + transport *WebRTCTransport, + scope network.ConnManagementScope, + + localPeer peer.ID, + localMultiaddr ma.Multiaddr, + + remotePeer peer.ID, + remoteKey ic.PubKey, + remoteMultiaddr ma.Multiaddr, + incomingDataChannels chan dataChannel, +) (*connection, error) { + ctx, cancel := context.WithCancel(context.Background()) + c := &connection{ + pc: pc, + transport: transport, + scope: scope, + + localPeer: localPeer, + localMultiaddr: localMultiaddr, + + remotePeer: remotePeer, + remoteKey: remoteKey, + remoteMultiaddr: remoteMultiaddr, + ctx: ctx, + cancel: cancel, + streams: make(map[uint16]*stream), + + acceptQueue: incomingDataChannels, + } + switch direction { + case network.DirInbound: + c.nextStreamID.Store(1) + case network.DirOutbound: + // stream ID 0 is used for the Noise handshake stream + c.nextStreamID.Store(2) + } + + pc.OnConnectionStateChange(c.onConnectionStateChange) + return c, nil +} + +// ConnState implements transport.CapableConn +func (c *connection) ConnState() network.ConnectionState { + return network.ConnectionState{Transport: "webrtc-direct"} +} + +// Close closes the underlying peerconnection. +func (c *connection) Close() error { + c.closeOnce.Do(func() { c.closeWithError(errors.New("connection closed")) }) + return nil +} + +// closeWithError is used to Close the connection when the underlying DTLS connection fails +func (c *connection) closeWithError(err error) { + c.closeErr = err + // cancel must be called after closeErr is set. This ensures interested goroutines waiting on + // ctx.Done can read closeErr without holding the conn lock. + c.cancel() + // closing peerconnection will close the datachannels associated with the streams + c.pc.Close() + + c.m.Lock() + streams := c.streams + c.streams = nil + c.m.Unlock() + for _, s := range streams { + s.closeForShutdown(err) + } + c.scope.Done() +} + +func (c *connection) IsClosed() bool { + return c.ctx.Err() != nil +} + +func (c *connection) OpenStream(ctx context.Context) (network.MuxedStream, error) { + if c.IsClosed() { + return nil, c.closeErr + } + + id := c.nextStreamID.Add(2) - 2 + if id > math.MaxUint16 { + return nil, errors.New("exhausted stream ID space") + } + streamID := uint16(id) + dc, err := c.pc.CreateDataChannel("", &webrtc.DataChannelInit{ID: &streamID}) + if err != nil { + return nil, err + } + rwc, err := c.detachChannel(ctx, dc) + if err != nil { + dc.Close() + return nil, fmt.Errorf("detach channel failed for stream(%d): %w", streamID, err) + } + str := newStream(dc, rwc, func() { c.removeStream(streamID) }) + if err := c.addStream(str); err != nil { + str.Reset() + return nil, fmt.Errorf("failed to add stream(%d) to connection: %w", streamID, err) + } + return str, nil +} + +func (c *connection) AcceptStream() (network.MuxedStream, error) { + select { + case <-c.ctx.Done(): + return nil, c.closeErr + case dc := <-c.acceptQueue: + str := newStream(dc.channel, dc.stream, func() { c.removeStream(*dc.channel.ID()) }) + if err := c.addStream(str); err != nil { + str.Reset() + return nil, err + } + return str, nil + } +} + +func (c *connection) LocalPeer() peer.ID { return c.localPeer } +func (c *connection) RemotePeer() peer.ID { return c.remotePeer } +func (c *connection) RemotePublicKey() ic.PubKey { return c.remoteKey } +func (c *connection) LocalMultiaddr() ma.Multiaddr { return c.localMultiaddr } +func (c *connection) RemoteMultiaddr() ma.Multiaddr { return c.remoteMultiaddr } +func (c *connection) Scope() network.ConnScope { return c.scope } +func (c *connection) Transport() tpt.Transport { return c.transport } + +func (c *connection) addStream(str *stream) error { + c.m.Lock() + defer c.m.Unlock() + if c.streams == nil { + return c.closeErr + } + if _, ok := c.streams[str.id]; ok { + return errors.New("stream ID already exists") + } + c.streams[str.id] = str + return nil +} + +func (c *connection) removeStream(id uint16) { + c.m.Lock() + defer c.m.Unlock() + delete(c.streams, id) +} + +func (c *connection) onConnectionStateChange(state webrtc.PeerConnectionState) { + if state == webrtc.PeerConnectionStateFailed || state == webrtc.PeerConnectionStateClosed { + c.closeOnce.Do(func() { + c.closeWithError(errConnectionTimeout{}) + }) + } +} + +// detachChannel detaches an outgoing channel by taking into account the context +// passed to `OpenStream` as well the closure of the underlying peerconnection +// +// The underlying SCTP stream for a datachannel implements a net.Conn interface. +// However, the datachannel creates a goroutine which continuously reads from +// the SCTP stream and surfaces the data using an OnMessage callback. +// +// The actual abstractions are as follows: webrtc.DataChannel +// wraps pion.DataChannel, which wraps sctp.Stream. +// +// The goroutine for reading, Detach method, +// and the OnMessage callback are present at the webrtc.DataChannel level. +// Detach provides us abstracted access to the underlying pion.DataChannel, +// which allows us to issue Read calls to the datachannel. +// This was desired because it was not feasible to introduce backpressure +// with the OnMessage callbacks. The tradeoff is a change in the semantics of +// the OnOpen callback, and having to force close Read locally. +func (c *connection) detachChannel(ctx context.Context, dc *webrtc.DataChannel) (datachannel.ReadWriteCloser, error) { + done := make(chan struct{}) + + var rwc datachannel.ReadWriteCloser + var err error + // OnOpen will return immediately for detached datachannels + // refer: https://github.com/pion/webrtc/blob/7ab3174640b3ce15abebc2516a2ca3939b5f105f/datachannel.go#L278-L282 + dc.OnOpen(func() { + rwc, err = dc.Detach() + // this is safe since the function should return instantly if the peerconnection is closed + close(done) + }) + select { + case <-c.ctx.Done(): + return nil, c.closeErr + case <-ctx.Done(): + return nil, ctx.Err() + case <-done: + return rwc, err + } +} diff --git a/go-libp2p/p2p/transport/webrtc/fingerprint.go b/go-libp2p/p2p/transport/webrtc/fingerprint.go new file mode 100644 index 0000000..fd71586 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/fingerprint.go @@ -0,0 +1,53 @@ +package libp2pwebrtc + +import ( + "crypto" + "crypto/x509" + "errors" + + ma "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multibase" + mh "github.com/multiformats/go-multihash" + "github.com/pion/webrtc/v3" +) + +// parseFingerprint is forked from pion to avoid bytes to string alloc, +// and to avoid the entire hex interspersing when we do not need it anyway + +var errHashUnavailable = errors.New("fingerprint: hash algorithm is not linked into the binary") + +// parseFingerprint creates a fingerprint for a certificate using the specified hash algorithm +func parseFingerprint(cert *x509.Certificate, algo crypto.Hash) ([]byte, error) { + if !algo.Available() { + return nil, errHashUnavailable + } + h := algo.New() + // Hash.Writer is specified to be never returning an error. + // https://golang.org/pkg/hash/#Hash + h.Write(cert.Raw) + return h.Sum(nil), nil +} + +func decodeRemoteFingerprint(maddr ma.Multiaddr) (*mh.DecodedMultihash, error) { + remoteFingerprintMultibase, err := maddr.ValueForProtocol(ma.P_CERTHASH) + if err != nil { + return nil, err + } + _, data, err := multibase.Decode(remoteFingerprintMultibase) + if err != nil { + return nil, err + } + return mh.Decode(data) +} + +func encodeDTLSFingerprint(fp webrtc.DTLSFingerprint) (string, error) { + digest, err := decodeInterspersedHexFromASCIIString(fp.Value) + if err != nil { + return "", err + } + encoded, err := mh.Encode(digest, mh.SHA2_256) + if err != nil { + return "", err + } + return multibase.Encode(multibase.Base64url, encoded) +} diff --git a/go-libp2p/p2p/transport/webrtc/hex.go b/go-libp2p/p2p/transport/webrtc/hex.go new file mode 100644 index 0000000..4820365 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/hex.go @@ -0,0 +1,70 @@ +package libp2pwebrtc + +// The code in this file is adapted from the Go standard library's hex package. +// As found in https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/encoding/hex/hex.go +// +// The reason we adapted the original code is to allow us to deal with interspersed requirements +// while at the same time hex encoding/decoding, without having to do so in two passes. + +import ( + "encoding/hex" + "errors" +) + +// encodeInterspersedHex encodes a byte slice into a string of hex characters, +// separating each encoded byte with a colon (':'). +// +// Example: { 0x01, 0x02, 0x03 } -> "01:02:03" +func encodeInterspersedHex(src []byte) string { + if len(src) == 0 { + return "" + } + s := hex.EncodeToString(src) + n := len(s) + // Determine number of colons + colons := n / 2 + if n%2 == 0 { + colons-- + } + buffer := make([]byte, n+colons) + + for i, j := 0, 0; i < n; i, j = i+2, j+3 { + copy(buffer[j:j+2], s[i:i+2]) + if j+3 < len(buffer) { + buffer[j+2] = ':' + } + } + return string(buffer) +} + +var errUnexpectedIntersperseHexChar = errors.New("unexpected character in interspersed hex string") + +// decodeInterspersedHexFromASCIIString decodes an ASCII string of hex characters into a byte slice, +// where the hex characters are expected to be separated by a colon (':'). +// +// NOTE that this function returns an error in case the input string contains non-ASCII characters. +// +// Example: "01:02:03" -> { 0x01, 0x02, 0x03 } +func decodeInterspersedHexFromASCIIString(s string) ([]byte, error) { + n := len(s) + buffer := make([]byte, n/3*2+n%3) + j := 0 + for i := 0; i < n; i++ { + if i%3 == 2 { + if s[i] != ':' { + return nil, errUnexpectedIntersperseHexChar + } + } else { + if s[i] == ':' { + return nil, errUnexpectedIntersperseHexChar + } + buffer[j] = s[i] + j++ + } + } + dst := make([]byte, hex.DecodedLen(len(buffer))) + if _, err := hex.Decode(dst, buffer); err != nil { + return nil, err + } + return dst, nil +} diff --git a/go-libp2p/p2p/transport/webrtc/hex_test.go b/go-libp2p/p2p/transport/webrtc/hex_test.go new file mode 100644 index 0000000..c8a7147 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/hex_test.go @@ -0,0 +1,132 @@ +package libp2pwebrtc + +import ( + "encoding/hex" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestEncodeInterspersedHex(t *testing.T) { + b, err := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + require.NoError(t, err) + require.Equal(t, "ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad", encodeInterspersedHex(b)) +} + +func BenchmarkEncodeInterspersedHex(b *testing.B) { + data, err := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + require.NoError(b, err) + + for i := 0; i < b.N; i++ { + encodeInterspersedHex(data) + } +} + +func TestDecodeInterpersedHexStringLowerCase(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad") + require.NoError(t, err) + require.Equal(t, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", hex.EncodeToString(b)) +} + +func TestDecodeInterpersedHexStringMixedCase(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("Ba:78:16:BF:8F:01:cf:ea:41:41:40:De:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:FF:61:f2:00:15:ad") + require.NoError(t, err) + require.Equal(t, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", hex.EncodeToString(b)) +} + +func TestDecodeInterpersedHexStringOneByte(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("ba") + require.NoError(t, err) + require.Equal(t, "ba", hex.EncodeToString(b)) +} + +func TestDecodeInterpersedHexBytesLowerCase(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad") + require.NoError(t, err) + require.Equal(t, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", hex.EncodeToString(b)) +} + +func BenchmarkDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := decodeInterspersedHexFromASCIIString("ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad") + require.NoError(b, err) + } +} + +func TestDecodeInterpersedHexBytesMixedCase(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("Ba:78:16:BF:8F:01:cf:ea:41:41:40:De:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:FF:61:f2:00:15:ad") + require.NoError(t, err) + require.Equal(t, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", hex.EncodeToString(b)) +} + +func TestDecodeInterpersedHexBytesOneByte(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("ba") + require.NoError(t, err) + require.Equal(t, "ba", hex.EncodeToString(b)) +} + +func TestEncodeInterperseHexNilSlice(t *testing.T) { + require.Equal(t, "", encodeInterspersedHex(nil)) + require.Equal(t, "", encodeInterspersedHex([]byte{})) +} + +func TestDecodeInterspersedHexEmpty(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("") + require.NoError(t, err) + require.Equal(t, []byte{}, b) +} + +func TestDecodeInterpersedHexFromASCIIStringEmpty(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("") + require.NoError(t, err) + require.Equal(t, []byte{}, b) +} + +func TestDecodeInterpersedHexInvalid(t *testing.T) { + for _, v := range []string{"0", "0000", "000"} { + _, err := decodeInterspersedHexFromASCIIString(v) + require.Error(t, err) + } +} + +func TestDecodeInterpersedHexValid(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("00") + require.NoError(t, err) + require.Equal(t, []byte{0}, b) +} + +func TestDecodeInterpersedHexFromASCIIStringInvalid(t *testing.T) { + for _, v := range []string{"0", "0000", "000"} { + _, err := decodeInterspersedHexFromASCIIString(v) + require.Error(t, err) + } +} + +func TestDecodeInterpersedHexFromASCIIStringValid(t *testing.T) { + b, err := decodeInterspersedHexFromASCIIString("00") + require.NoError(t, err) + require.Equal(t, []byte{0}, b) +} + +func FuzzInterpersedHex(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + decoded, err := decodeInterspersedHexFromASCIIString(string(b)) + if err != nil { + return + } + encoded := encodeInterspersedHex(decoded) + require.Equal(t, strings.ToLower(string(b)), encoded) + }) +} + +func FuzzInterspersedHexASCII(f *testing.F) { + f.Fuzz(func(t *testing.T, s string) { + decoded, err := decodeInterspersedHexFromASCIIString(s) + if err != nil { + return + } + encoded := encodeInterspersedHex(decoded) + require.Equal(t, strings.ToLower(s), encoded) + }) +} diff --git a/go-libp2p/p2p/transport/webrtc/listener.go b/go-libp2p/p2p/transport/webrtc/listener.go new file mode 100644 index 0000000..1834fc8 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/listener.go @@ -0,0 +1,350 @@ +package libp2pwebrtc + +import ( + "context" + "crypto" + "encoding/hex" + "errors" + "fmt" + "net" + "strings" + "sync" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + tpt "github.com/libp2p/go-libp2p/core/transport" + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/udpmux" + + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multihash" + "github.com/pion/webrtc/v3" +) + +type connMultiaddrs struct { + local, remote ma.Multiaddr +} + +var _ network.ConnMultiaddrs = &connMultiaddrs{} + +func (c *connMultiaddrs) LocalMultiaddr() ma.Multiaddr { return c.local } +func (c *connMultiaddrs) RemoteMultiaddr() ma.Multiaddr { return c.remote } + +const ( + candidateSetupTimeout = 20 * time.Second + DefaultMaxInFlightConnections = 10 +) + +type listener struct { + transport *WebRTCTransport + + mux *udpmux.UDPMux + + config webrtc.Configuration + localFingerprint webrtc.DTLSFingerprint + localFingerprintMultibase string + + localAddr net.Addr + localMultiaddr ma.Multiaddr + + // buffered incoming connections + acceptQueue chan tpt.CapableConn + + // used to control the lifecycle of the listener + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup +} + +var _ tpt.Listener = &listener{} + +func newListener(transport *WebRTCTransport, laddr ma.Multiaddr, socket net.PacketConn, config webrtc.Configuration) (*listener, error) { + localFingerprints, err := config.Certificates[0].GetFingerprints() + if err != nil { + return nil, err + } + + localMh, err := hex.DecodeString(strings.ReplaceAll(localFingerprints[0].Value, ":", "")) + if err != nil { + return nil, err + } + localMhBuf, err := multihash.Encode(localMh, multihash.SHA2_256) + if err != nil { + return nil, err + } + localFpMultibase, err := multibase.Encode(multibase.Base64url, localMhBuf) + if err != nil { + return nil, err + } + + l := &listener{ + transport: transport, + config: config, + localFingerprint: localFingerprints[0], + localFingerprintMultibase: localFpMultibase, + localMultiaddr: laddr, + localAddr: socket.LocalAddr(), + acceptQueue: make(chan tpt.CapableConn), + } + + l.ctx, l.cancel = context.WithCancel(context.Background()) + l.mux = udpmux.NewUDPMux(socket) + l.mux.Start() + + l.wg.Add(1) + go func() { + defer l.wg.Done() + l.listen() + }() + + return l, err +} + +func (l *listener) listen() { + // Accepting a connection requires instantiating a peerconnection and a noise connection + // which is expensive. We therefore limit the number of in-flight connection requests. A + // connection is considered to be in flight from the instant it is handled until it is + // dequeued by a call to Accept, or errors out in some way. + inFlightSemaphore := make(chan struct{}, l.transport.maxInFlightConnections) + for { + select { + case inFlightSemaphore <- struct{}{}: + case <-l.ctx.Done(): + return + } + + candidate, err := l.mux.Accept(l.ctx) + if err != nil { + if l.ctx.Err() == nil { + log.Debugf("accepting candidate failed: %s", err) + } + return + } + + go func() { + defer func() { <-inFlightSemaphore }() + + ctx, cancel := context.WithTimeout(l.ctx, candidateSetupTimeout) + defer cancel() + + conn, err := l.handleCandidate(ctx, candidate) + if err != nil { + l.mux.RemoveConnByUfrag(candidate.Ufrag) + log.Debugf("could not accept connection: %s: %v", candidate.Ufrag, err) + return + } + + select { + case <-ctx.Done(): + log.Warn("could not push connection: ctx done") + conn.Close() + case l.acceptQueue <- conn: + // acceptQueue is an unbuffered channel, so this blocks until the connection is accepted. + } + }() + } +} + +func (l *listener) handleCandidate(ctx context.Context, candidate udpmux.Candidate) (tpt.CapableConn, error) { + remoteMultiaddr, err := manet.FromNetAddr(candidate.Addr) + if err != nil { + return nil, err + } + if l.transport.gater != nil { + localAddr, _ := ma.SplitFunc(l.localMultiaddr, func(c ma.Component) bool { return c.Protocol().Code == ma.P_CERTHASH }) + if !l.transport.gater.InterceptAccept(&connMultiaddrs{local: localAddr, remote: remoteMultiaddr}) { + // The connection attempt is rejected before we can send the client an error. + // This means that the connection attempt will time out. + return nil, errors.New("connection gated") + } + } + scope, err := l.transport.rcmgr.OpenConnection(network.DirInbound, false, remoteMultiaddr) + if err != nil { + return nil, err + } + conn, err := l.setupConnection(ctx, scope, remoteMultiaddr, candidate) + if err != nil { + scope.Done() + return nil, err + } + if l.transport.gater != nil && !l.transport.gater.InterceptSecured(network.DirInbound, conn.RemotePeer(), conn) { + conn.Close() + return nil, errors.New("connection gated") + } + return conn, nil +} + +func (l *listener) setupConnection( + ctx context.Context, scope network.ConnManagementScope, + remoteMultiaddr ma.Multiaddr, candidate udpmux.Candidate, +) (tConn tpt.CapableConn, err error) { + var w webRTCConnection + defer func() { + if err != nil { + if w.PeerConnection != nil { + _ = w.PeerConnection.Close() + } + if tConn != nil { + _ = tConn.Close() + } + } + }() + + settingEngine := webrtc.SettingEngine{LoggerFactory: pionLoggerFactory} + settingEngine.SetAnsweringDTLSRole(webrtc.DTLSRoleServer) + settingEngine.SetICECredentials(candidate.Ufrag, candidate.Ufrag) + settingEngine.SetLite(true) + settingEngine.SetICEUDPMux(l.mux) + settingEngine.SetIncludeLoopbackCandidate(true) + settingEngine.DisableCertificateFingerprintVerification(true) + settingEngine.SetICETimeouts( + l.transport.peerConnectionTimeouts.Disconnect, + l.transport.peerConnectionTimeouts.Failed, + l.transport.peerConnectionTimeouts.Keepalive, + ) + // This is higher than the path MTU due to a bug in the sctp chunking logic. + // Remove this after https://github.com/pion/sctp/pull/301 is included + // in a release. + settingEngine.SetReceiveMTU(udpmux.ReceiveBufSize) + settingEngine.DetachDataChannels() + settingEngine.SetSCTPMaxReceiveBufferSize(sctpReceiveBufferSize) + if err := scope.ReserveMemory(sctpReceiveBufferSize, network.ReservationPriorityMedium); err != nil { + return nil, err + } + + w, err = newWebRTCConnection(settingEngine, l.config) + if err != nil { + return nil, fmt.Errorf("instantiating peer connection failed: %w", err) + } + + errC := addOnConnectionStateChangeCallback(w.PeerConnection) + // Infer the client SDP from the incoming STUN message by setting the ice-ufrag. + if err := w.PeerConnection.SetRemoteDescription(webrtc.SessionDescription{ + SDP: createClientSDP(candidate.Addr, candidate.Ufrag), + Type: webrtc.SDPTypeOffer, + }); err != nil { + return nil, err + } + answer, err := w.PeerConnection.CreateAnswer(nil) + if err != nil { + return nil, err + } + if err := w.PeerConnection.SetLocalDescription(answer); err != nil { + return nil, err + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case err := <-errC: + if err != nil { + return nil, fmt.Errorf("peer connection failed for ufrag: %s", candidate.Ufrag) + } + } + + // Run the noise handshake. + rwc, err := detachHandshakeDataChannel(ctx, w.HandshakeDataChannel) + if err != nil { + return nil, err + } + handshakeChannel := newStream(w.HandshakeDataChannel, rwc, func() {}) + // we do not yet know A's peer ID so accept any inbound + remotePubKey, err := l.transport.noiseHandshake(ctx, w.PeerConnection, handshakeChannel, "", crypto.SHA256, true) + if err != nil { + return nil, err + } + remotePeer, err := peer.IDFromPublicKey(remotePubKey) + if err != nil { + return nil, err + } + // earliest point where we know the remote's peerID + if err := scope.SetPeer(remotePeer); err != nil { + return nil, err + } + + localMultiaddrWithoutCerthash, _ := ma.SplitFunc(l.localMultiaddr, func(c ma.Component) bool { return c.Protocol().Code == ma.P_CERTHASH }) + conn, err := newConnection( + network.DirInbound, + w.PeerConnection, + l.transport, + scope, + l.transport.localPeerId, + localMultiaddrWithoutCerthash, + remotePeer, + remotePubKey, + remoteMultiaddr, + w.IncomingDataChannels, + ) + if err != nil { + return nil, err + } + + return conn, err +} + +func (l *listener) Accept() (tpt.CapableConn, error) { + select { + case <-l.ctx.Done(): + return nil, tpt.ErrListenerClosed + case conn := <-l.acceptQueue: + return conn, nil + } +} + +func (l *listener) Close() error { + select { + case <-l.ctx.Done(): + default: + } + l.cancel() + l.mux.Close() + l.wg.Wait() +loop: + for { + select { + case conn := <-l.acceptQueue: + conn.Close() + default: + break loop + } + } + return nil +} + +func (l *listener) Addr() net.Addr { + return l.localAddr +} + +func (l *listener) Multiaddr() ma.Multiaddr { + return l.localMultiaddr +} + +// addOnConnectionStateChangeCallback adds the OnConnectionStateChange to the PeerConnection. +// The channel returned here: +// * is closed when the state changes to Connection +// * receives an error when the state changes to Failed +// * doesn't receive anything (nor is closed) when the state changes to Disconnected +func addOnConnectionStateChangeCallback(pc *webrtc.PeerConnection) <-chan error { + errC := make(chan error, 1) + var once sync.Once + pc.OnConnectionStateChange(func(state webrtc.PeerConnectionState) { + switch state { + case webrtc.PeerConnectionStateConnected: + once.Do(func() { close(errC) }) + case webrtc.PeerConnectionStateFailed: + once.Do(func() { + errC <- errors.New("peerconnection failed") + close(errC) + }) + case webrtc.PeerConnectionStateDisconnected: + // the connection can move to a disconnected state and back to a connected state without ICE renegotiation. + // This could happen when underlying UDP packets are lost, and therefore the connection moves to the disconnected state. + // If the connection then receives packets on the connection, it can move back to the connected state. + // If no packets are received until the failed timeout is triggered, the connection moves to the failed state. + log.Warn("peerconnection disconnected") + } + }) + return errC +} diff --git a/go-libp2p/p2p/transport/webrtc/logger.go b/go-libp2p/p2p/transport/webrtc/logger.go new file mode 100644 index 0000000..ac9fab7 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/logger.go @@ -0,0 +1,58 @@ +package libp2pwebrtc + +import ( + logging "github.com/ipfs/go-log/v2" + pionLogging "github.com/pion/logging" +) + +var log = logging.Logger("webrtc-transport") + +// pionLog is the logger provided to pion for internal logging +var pionLog = logging.Logger("webrtc-transport-pion") + +// pionLogger wraps the StandardLogger interface to provide a LeveledLogger interface +// as expected by pion +type pionLogger struct { + logging.StandardLogger +} + +var pLog = pionLogger{pionLog} + +var _ pionLogging.LeveledLogger = pLog + +func (l pionLogger) Debug(s string) { + l.StandardLogger.Debug(s) +} + +func (l pionLogger) Error(s string) { + l.StandardLogger.Error(s) +} + +func (l pionLogger) Info(s string) { + l.StandardLogger.Info(s) +} +func (l pionLogger) Warn(s string) { + l.StandardLogger.Warn(s) +} + +func (l pionLogger) Trace(s string) { + l.StandardLogger.Debug(s) +} + +func (l pionLogger) Tracef(s string, args ...interface{}) { + l.StandardLogger.Debugf(s, args...) +} + +// loggerFactory returns pLog for all new logger instances +type loggerFactory struct{} + +// NewLogger returns pLog for all new logger instances. Internally pion creates lots of +// separate logging objects unnecessarily. To avoid the allocations we use a single log +// object for all of pion logging. +func (loggerFactory) NewLogger(scope string) pionLogging.LeveledLogger { + return pLog +} + +var _ pionLogging.LoggerFactory = loggerFactory{} + +var pionLoggerFactory = loggerFactory{} diff --git a/go-libp2p/p2p/transport/webrtc/message.go b/go-libp2p/p2p/transport/webrtc/message.go new file mode 100644 index 0000000..8b57fc8 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/message.go @@ -0,0 +1,3 @@ +package libp2pwebrtc + +//go:generate protoc --go_out=. --go_opt=Mpb/message.proto=./pb pb/message.proto diff --git a/go-libp2p/p2p/transport/webrtc/pb/generate.go b/go-libp2p/p2p/transport/webrtc/pb/generate.go new file mode 100644 index 0000000..5785a95 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/pb/generate.go @@ -0,0 +1,3 @@ +package pb + +//go:generate protoc --go_out=. --go_opt=paths=source_relative -I . message.proto diff --git a/go-libp2p/p2p/transport/webrtc/pb/message.pb.go b/go-libp2p/p2p/transport/webrtc/pb/message.pb.go new file mode 100644 index 0000000..384bddd --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/pb/message.pb.go @@ -0,0 +1,231 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: message.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Message_Flag int32 + +const ( + // The sender will no longer send messages on the stream. + Message_FIN Message_Flag = 0 + // The sender will no longer read messages on the stream. Incoming data is + // being discarded on receipt. + Message_STOP_SENDING Message_Flag = 1 + // The sender abruptly terminates the sending part of the stream. The + // receiver can discard any data that it already received on that stream. + Message_RESET Message_Flag = 2 + // Sending the FIN_ACK flag acknowledges the previous receipt of a message + // with the FIN flag set. Receiving a FIN_ACK flag gives the recipient + // confidence that the remote has received all sent messages. + Message_FIN_ACK Message_Flag = 3 +) + +// Enum value maps for Message_Flag. +var ( + Message_Flag_name = map[int32]string{ + 0: "FIN", + 1: "STOP_SENDING", + 2: "RESET", + 3: "FIN_ACK", + } + Message_Flag_value = map[string]int32{ + "FIN": 0, + "STOP_SENDING": 1, + "RESET": 2, + "FIN_ACK": 3, + } +) + +func (x Message_Flag) Enum() *Message_Flag { + p := new(Message_Flag) + *p = x + return p +} + +func (x Message_Flag) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Message_Flag) Descriptor() protoreflect.EnumDescriptor { + return file_message_proto_enumTypes[0].Descriptor() +} + +func (Message_Flag) Type() protoreflect.EnumType { + return &file_message_proto_enumTypes[0] +} + +func (x Message_Flag) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *Message_Flag) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = Message_Flag(num) + return nil +} + +// Deprecated: Use Message_Flag.Descriptor instead. +func (Message_Flag) EnumDescriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{0, 0} +} + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Flag *Message_Flag `protobuf:"varint,1,opt,name=flag,enum=Message_Flag" json:"flag,omitempty"` + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` +} + +func (x *Message) Reset() { + *x = Message{} + if protoimpl.UnsafeEnabled { + mi := &file_message_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{0} +} + +func (x *Message) GetFlag() Message_Flag { + if x != nil && x.Flag != nil { + return *x.Flag + } + return Message_FIN +} + +func (x *Message) GetMessage() []byte { + if x != nil { + return x.Message + } + return nil +} + +var File_message_proto protoreflect.FileDescriptor + +var file_message_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x81, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x66, + 0x6c, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x39, 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, + 0x12, 0x07, 0x0a, 0x03, 0x46, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x4f, + 0x50, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, + 0x45, 0x53, 0x45, 0x54, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x49, 0x4e, 0x5f, 0x41, 0x43, + 0x4b, 0x10, 0x03, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, + 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2f, 0x70, 0x62, +} + +var ( + file_message_proto_rawDescOnce sync.Once + file_message_proto_rawDescData = file_message_proto_rawDesc +) + +func file_message_proto_rawDescGZIP() []byte { + file_message_proto_rawDescOnce.Do(func() { + file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) + }) + return file_message_proto_rawDescData +} + +var file_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_message_proto_goTypes = []interface{}{ + (Message_Flag)(0), // 0: Message.Flag + (*Message)(nil), // 1: Message +} +var file_message_proto_depIdxs = []int32{ + 0, // 0: Message.flag:type_name -> Message.Flag + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_message_proto_init() } +func file_message_proto_init() { + if File_message_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_message_proto_rawDesc, + NumEnums: 1, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_message_proto_goTypes, + DependencyIndexes: file_message_proto_depIdxs, + EnumInfos: file_message_proto_enumTypes, + MessageInfos: file_message_proto_msgTypes, + }.Build() + File_message_proto = out.File + file_message_proto_rawDesc = nil + file_message_proto_goTypes = nil + file_message_proto_depIdxs = nil +} diff --git a/go-libp2p/p2p/transport/webrtc/pb/message.proto b/go-libp2p/p2p/transport/webrtc/pb/message.proto new file mode 100644 index 0000000..aab885b --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/pb/message.proto @@ -0,0 +1,24 @@ +syntax = "proto2"; + +option go_package = "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb"; + +message Message { + enum Flag { + // The sender will no longer send messages on the stream. + FIN = 0; + // The sender will no longer read messages on the stream. Incoming data is + // being discarded on receipt. + STOP_SENDING = 1; + // The sender abruptly terminates the sending part of the stream. The + // receiver can discard any data that it already received on that stream. + RESET = 2; + // Sending the FIN_ACK flag acknowledges the previous receipt of a message + // with the FIN flag set. Receiving a FIN_ACK flag gives the recipient + // confidence that the remote has received all sent messages. + FIN_ACK = 3; + } + + optional Flag flag=1; + + optional bytes message = 2; +} diff --git a/go-libp2p/p2p/transport/webrtc/sdp.go b/go-libp2p/p2p/transport/webrtc/sdp.go new file mode 100644 index 0000000..878b668 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/sdp.go @@ -0,0 +1,143 @@ +package libp2pwebrtc + +import ( + "crypto" + "fmt" + "net" + "strings" + + "github.com/multiformats/go-multihash" +) + +// clientSDP describes an SDP format string which can be used +// to infer a client's SDP offer from the incoming STUN message. +// The fingerprint used to render a client SDP is arbitrary since +// it fingerprint verification is disabled in favour of a noise +// handshake. The max message size is fixed to 16384 bytes. +const clientSDP = `v=0 +o=- 0 0 IN %[1]s %[2]s +s=- +c=IN %[1]s %[2]s +t=0 0 + +m=application %[3]d UDP/DTLS/SCTP webrtc-datachannel +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:%[4]s +a=ice-pwd:%[4]s +a=fingerprint:sha-256 ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad +a=setup:actpass +a=sctp-port:5000 +a=max-message-size:16384 +` + +func createClientSDP(addr *net.UDPAddr, ufrag string) string { + ipVersion := "IP4" + if addr.IP.To4() == nil { + ipVersion = "IP6" + } + return fmt.Sprintf( + clientSDP, + ipVersion, + addr.IP, + addr.Port, + ufrag, + ) +} + +// serverSDP defines an SDP format string used by a dialer +// to infer the SDP answer of a server based on the provided +// multiaddr, and the locally set ICE credentials. The max +// message size is fixed to 16384 bytes. +const serverSDP = `v=0 +o=- 0 0 IN %[1]s %[2]s +s=- +t=0 0 +a=ice-lite +m=application %[3]d UDP/DTLS/SCTP webrtc-datachannel +c=IN %[1]s %[2]s +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:%[4]s +a=ice-pwd:%[4]s +a=fingerprint:%[5]s + +a=setup:passive +a=sctp-port:5000 +a=max-message-size:16384 +a=candidate:1 1 UDP 1 %[2]s %[3]d typ host +a=end-of-candidates +` + +func createServerSDP(addr *net.UDPAddr, ufrag string, fingerprint multihash.DecodedMultihash) (string, error) { + ipVersion := "IP4" + if addr.IP.To4() == nil { + ipVersion = "IP6" + } + + sdpString, err := getSupportedSDPString(fingerprint.Code) + if err != nil { + return "", err + } + + var builder strings.Builder + builder.Grow(len(fingerprint.Digest)*3 + 8) + builder.WriteString(sdpString) + builder.WriteByte(' ') + builder.WriteString(encodeInterspersedHex(fingerprint.Digest)) + fp := builder.String() + + return fmt.Sprintf( + serverSDP, + ipVersion, + addr.IP, + addr.Port, + ufrag, + fp, + ), nil +} + +// getSupportedSDPHash converts a multihash code to the +// corresponding crypto.Hash for supported protocols. If a +// crypto.Hash cannot be found, it returns `(0, false)` +func getSupportedSDPHash(code uint64) (crypto.Hash, bool) { + switch code { + case multihash.MD5: + return crypto.MD5, true + case multihash.SHA1: + return crypto.SHA1, true + case multihash.SHA3_224: + return crypto.SHA3_224, true + case multihash.SHA2_256: + return crypto.SHA256, true + case multihash.SHA3_384: + return crypto.SHA3_384, true + case multihash.SHA2_512: + return crypto.SHA512, true + default: + return 0, false + } +} + +// getSupportedSDPString converts a multihash code +// to a string format recognised by pion for fingerprint +// algorithms +func getSupportedSDPString(code uint64) (string, error) { + // values based on (cryto.Hash).String() + switch code { + case multihash.MD5: + return "md5", nil + case multihash.SHA1: + return "sha-1", nil + case multihash.SHA3_224: + return "sha3-224", nil + case multihash.SHA2_256: + return "sha-256", nil + case multihash.SHA3_384: + return "sha3-384", nil + case multihash.SHA2_512: + return "sha-512", nil + default: + return "", fmt.Errorf("unsupported hash code (%d)", code) + } +} diff --git a/go-libp2p/p2p/transport/webrtc/sdp_test.go b/go-libp2p/p2p/transport/webrtc/sdp_test.go new file mode 100644 index 0000000..2e7ac5b --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/sdp_test.go @@ -0,0 +1,101 @@ +package libp2pwebrtc + +import ( + "encoding/hex" + "net" + "testing" + + "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/require" +) + +const expectedServerSDP = `v=0 +o=- 0 0 IN IP4 0.0.0.0 +s=- +t=0 0 +a=ice-lite +m=application 37826 UDP/DTLS/SCTP webrtc-datachannel +c=IN IP4 0.0.0.0 +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581 +a=ice-pwd:d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581 +a=fingerprint:sha-256 ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad + +a=setup:passive +a=sctp-port:5000 +a=max-message-size:16384 +a=candidate:1 1 UDP 1 0.0.0.0 37826 typ host +a=end-of-candidates +` + +func TestRenderServerSDP(t *testing.T) { + encoded, err := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + require.NoError(t, err) + + testMultihash := multihash.DecodedMultihash{ + Code: multihash.SHA2_256, + Name: multihash.Codes[multihash.SHA2_256], + Digest: encoded, + Length: len(encoded), + } + addr := &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 37826} + ufrag := "d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581" + fingerprint := testMultihash + + sdp, err := createServerSDP(addr, ufrag, fingerprint) + require.NoError(t, err) + require.Equal(t, expectedServerSDP, sdp) +} + +const expectedClientSDP = `v=0 +o=- 0 0 IN IP4 0.0.0.0 +s=- +c=IN IP4 0.0.0.0 +t=0 0 + +m=application 37826 UDP/DTLS/SCTP webrtc-datachannel +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581 +a=ice-pwd:d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581 +a=fingerprint:sha-256 ba:78:16:bf:8f:01:cf:ea:41:41:40:de:5d:ae:22:23:b0:03:61:a3:96:17:7a:9c:b4:10:ff:61:f2:00:15:ad +a=setup:actpass +a=sctp-port:5000 +a=max-message-size:16384 +` + +func TestRenderClientSDP(t *testing.T) { + addr := &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 37826} + ufrag := "d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581" + sdp := createClientSDP(addr, ufrag) + require.Equal(t, expectedClientSDP, sdp) +} + +func BenchmarkRenderClientSDP(b *testing.B) { + addr := &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 37826} + ufrag := "d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581" + + for i := 0; i < b.N; i++ { + createClientSDP(addr, ufrag) + } +} + +func BenchmarkRenderServerSDP(b *testing.B) { + encoded, _ := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + + testMultihash := multihash.DecodedMultihash{ + Code: multihash.SHA2_256, + Name: multihash.Codes[multihash.SHA2_256], + Digest: encoded, + Length: len(encoded), + } + addr := &net.UDPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 37826} + ufrag := "d2c0fc07-8bb3-42ae-bae2-a6fce8a0b581" + fingerprint := testMultihash + + for i := 0; i < b.N; i++ { + createServerSDP(addr, ufrag, fingerprint) + } + +} diff --git a/go-libp2p/p2p/transport/webrtc/stream.go b/go-libp2p/p2p/transport/webrtc/stream.go new file mode 100644 index 0000000..56f869f --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/stream.go @@ -0,0 +1,281 @@ +package libp2pwebrtc + +import ( + "errors" + "os" + "sync" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb" + "github.com/libp2p/go-msgio/pbio" + + "github.com/pion/datachannel" + "github.com/pion/webrtc/v3" +) + +const ( + // maxMessageSize is the maximum message size of the Protobuf message we send / receive. + maxMessageSize = 16384 + // maxSendBuffer is the maximum data we enqueue on the underlying data channel for writes. + // The underlying SCTP layer has an unbounded buffer for writes. We limit the amount enqueued + // per stream is limited to avoid a single stream monopolizing the entire connection. + maxSendBuffer = 2 * maxMessageSize + // sendBufferLowThreshold is the threshold below which we write more data on the underlying + // data channel. We want a notification as soon as we can write 1 full sized message. + sendBufferLowThreshold = maxSendBuffer - maxMessageSize + // maxTotalControlMessagesSize is the maximum total size of all control messages we will + // write on this stream. + // 4 control messages of size 10 bytes + 10 bytes buffer. This number doesn't need to be + // exact. In the worst case, we enqueue these many bytes more in the webrtc peer connection + // send queue. + maxTotalControlMessagesSize = 50 + + // Proto overhead assumption is 5 bytes + protoOverhead = 5 + // Varint overhead is assumed to be 2 bytes. This is safe since + // 1. This is only used and when writing message, and + // 2. We only send messages in chunks of `maxMessageSize - varintOverhead` + // which includes the data and the protobuf header. Since `maxMessageSize` + // is less than or equal to 2 ^ 14, the varint will not be more than + // 2 bytes in length. + varintOverhead = 2 + // maxFINACKWait is the maximum amount of time a stream will wait to read + // FIN_ACK before closing the data channel + maxFINACKWait = 10 * time.Second +) + +type receiveState uint8 + +const ( + receiveStateReceiving receiveState = iota + receiveStateDataRead // received and read the FIN + receiveStateReset // either by calling CloseRead locally, or by receiving +) + +type sendState uint8 + +const ( + sendStateSending sendState = iota + sendStateDataSent + sendStateDataReceived + sendStateReset +) + +// Package pion detached data channel into a net.Conn +// and then a network.MuxedStream +type stream struct { + mx sync.Mutex + + // readerMx ensures that only a single goroutine reads from the reader. Read is not threadsafe + // But we may need to read from reader for control messages from a different goroutine. + readerMx sync.Mutex + reader pbio.Reader + + // this buffer is limited up to a single message. Reason we need it + // is because a reader might read a message midway, and so we need a + // wait to buffer that for as long as the remaining part is not (yet) read + nextMessage *pb.Message + receiveState receiveState + + writer pbio.Writer // concurrent writes prevented by mx + writeStateChanged chan struct{} + sendState sendState + writeDeadline time.Time + + controlMessageReaderOnce sync.Once + // controlMessageReaderEndTime is the end time for reading FIN_ACK from the control + // message reader. We cannot rely on SetReadDeadline to do this since that is prone to + // race condition where a previous deadline timer fires after the latest call to + // SetReadDeadline + // See: https://github.com/pion/sctp/pull/290 + controlMessageReaderEndTime time.Time + + onDoneOnce sync.Once + onDone func() + id uint16 // for logging purposes + dataChannel *datachannel.DataChannel + closeForShutdownErr error +} + +var _ network.MuxedStream = &stream{} + +func newStream( + channel *webrtc.DataChannel, + rwc datachannel.ReadWriteCloser, + onDone func(), +) *stream { + s := &stream{ + reader: pbio.NewDelimitedReader(rwc, maxMessageSize), + writer: pbio.NewDelimitedWriter(rwc), + writeStateChanged: make(chan struct{}, 1), + id: *channel.ID(), + dataChannel: rwc.(*datachannel.DataChannel), + onDone: onDone, + } + s.dataChannel.SetBufferedAmountLowThreshold(sendBufferLowThreshold) + s.dataChannel.OnBufferedAmountLow(func() { + s.notifyWriteStateChanged() + + }) + return s +} + +func (s *stream) Close() error { + s.mx.Lock() + isClosed := s.closeForShutdownErr != nil + s.mx.Unlock() + if isClosed { + return nil + } + defer s.cleanup() + closeWriteErr := s.CloseWrite() + closeReadErr := s.CloseRead() + if closeWriteErr != nil || closeReadErr != nil { + s.Reset() + return errors.Join(closeWriteErr, closeReadErr) + } + + s.mx.Lock() + if s.controlMessageReaderEndTime.IsZero() { + s.controlMessageReaderEndTime = time.Now().Add(maxFINACKWait) + s.setDataChannelReadDeadline(time.Now().Add(-1 * time.Hour)) + } + s.mx.Unlock() + return nil +} + +func (s *stream) Reset() error { + s.mx.Lock() + isClosed := s.closeForShutdownErr != nil + s.mx.Unlock() + if isClosed { + return nil + } + + defer s.cleanup() + cancelWriteErr := s.cancelWrite() + closeReadErr := s.CloseRead() + s.setDataChannelReadDeadline(time.Now().Add(-1 * time.Hour)) + return errors.Join(closeReadErr, cancelWriteErr) +} + +func (s *stream) closeForShutdown(closeErr error) { + defer s.cleanup() + + s.mx.Lock() + defer s.mx.Unlock() + + s.closeForShutdownErr = closeErr + s.notifyWriteStateChanged() +} + +func (s *stream) SetDeadline(t time.Time) error { + _ = s.SetReadDeadline(t) + return s.SetWriteDeadline(t) +} + +// processIncomingFlag process the flag on an incoming message +// It needs to be called while the mutex is locked. +func (s *stream) processIncomingFlag(flag *pb.Message_Flag) { + if flag == nil { + return + } + + switch *flag { + case pb.Message_STOP_SENDING: + // We must process STOP_SENDING after sending a FIN(sendStateDataSent). Remote peer + // may not send a FIN_ACK once it has sent a STOP_SENDING + if s.sendState == sendStateSending || s.sendState == sendStateDataSent { + s.sendState = sendStateReset + } + s.notifyWriteStateChanged() + case pb.Message_FIN_ACK: + s.sendState = sendStateDataReceived + s.notifyWriteStateChanged() + case pb.Message_FIN: + if s.receiveState == receiveStateReceiving { + s.receiveState = receiveStateDataRead + } + if err := s.writer.WriteMsg(&pb.Message{Flag: pb.Message_FIN_ACK.Enum()}); err != nil { + log.Debugf("failed to send FIN_ACK: %s", err) + // Remote has finished writing all the data It'll stop waiting for the + // FIN_ACK eventually or will be notified when we close the datachannel + } + s.spawnControlMessageReader() + case pb.Message_RESET: + if s.receiveState == receiveStateReceiving { + s.receiveState = receiveStateReset + } + s.spawnControlMessageReader() + } +} + +// spawnControlMessageReader is used for processing control messages after the reader is closed. +func (s *stream) spawnControlMessageReader() { + s.controlMessageReaderOnce.Do(func() { + // Spawn a goroutine to ensure that we're not holding any locks + go func() { + // cleanup the sctp deadline timer goroutine + defer s.setDataChannelReadDeadline(time.Time{}) + + defer s.dataChannel.Close() + + // Unblock any Read call waiting on reader.ReadMsg + s.setDataChannelReadDeadline(time.Now().Add(-1 * time.Hour)) + + s.readerMx.Lock() + // We have the lock: any readers blocked on reader.ReadMsg have exited. + s.mx.Lock() + defer s.mx.Unlock() + // From this point onwards only this goroutine will do reader.ReadMsg. + // We just wanted to ensure any exising readers have exited. + // Read calls from this point onwards will exit immediately on checking + // s.readState + s.readerMx.Unlock() + + if s.nextMessage != nil { + s.processIncomingFlag(s.nextMessage.Flag) + s.nextMessage = nil + } + var msg pb.Message + for { + // Connection closed. No need to cleanup the data channel. + if s.closeForShutdownErr != nil { + return + } + // Write half of the stream completed. + if s.sendState == sendStateDataReceived || s.sendState == sendStateReset { + return + } + // FIN_ACK wait deadling exceeded. + if !s.controlMessageReaderEndTime.IsZero() && time.Now().After(s.controlMessageReaderEndTime) { + return + } + + s.setDataChannelReadDeadline(s.controlMessageReaderEndTime) + s.mx.Unlock() + err := s.reader.ReadMsg(&msg) + s.mx.Lock() + if err != nil { + // We have to manually manage deadline exceeded errors since pion/sctp can + // return deadline exceeded error for cancelled deadlines + // see: https://github.com/pion/sctp/pull/290/files + if errors.Is(err, os.ErrDeadlineExceeded) { + continue + } + return + } + s.processIncomingFlag(msg.Flag) + } + }() + }) +} + +func (s *stream) cleanup() { + s.onDoneOnce.Do(func() { + if s.onDone != nil { + s.onDone() + } + }) +} diff --git a/go-libp2p/p2p/transport/webrtc/stream_read.go b/go-libp2p/p2p/transport/webrtc/stream_read.go new file mode 100644 index 0000000..80d99ea --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/stream_read.go @@ -0,0 +1,113 @@ +package libp2pwebrtc + +import ( + "io" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb" +) + +func (s *stream) Read(b []byte) (int, error) { + s.readerMx.Lock() + defer s.readerMx.Unlock() + + s.mx.Lock() + defer s.mx.Unlock() + + if s.closeForShutdownErr != nil { + return 0, s.closeForShutdownErr + } + switch s.receiveState { + case receiveStateDataRead: + return 0, io.EOF + case receiveStateReset: + return 0, network.ErrReset + } + + if len(b) == 0 { + return 0, nil + } + + var read int + for { + if s.nextMessage == nil { + // load the next message + s.mx.Unlock() + var msg pb.Message + err := s.reader.ReadMsg(&msg) + s.mx.Lock() + if err != nil { + // connection was closed + if s.closeForShutdownErr != nil { + return 0, s.closeForShutdownErr + } + if err == io.EOF { + // if the channel was properly closed, return EOF + if s.receiveState == receiveStateDataRead { + return 0, io.EOF + } + // This case occurs when remote closes the datachannel without writing a FIN + // message. Some implementations discard the buffered data on closing the + // datachannel. For these implementations a stream reset will be observed as an + // abrupt closing of the datachannel. + s.receiveState = receiveStateReset + return 0, network.ErrReset + } + if s.receiveState == receiveStateReset { + return 0, network.ErrReset + } + if s.receiveState == receiveStateDataRead { + return 0, io.EOF + } + return 0, err + } + s.nextMessage = &msg + } + + if len(s.nextMessage.Message) > 0 { + n := copy(b, s.nextMessage.Message) + read += n + s.nextMessage.Message = s.nextMessage.Message[n:] + return read, nil + } + + // process flags on the message after reading all the data + s.processIncomingFlag(s.nextMessage.Flag) + s.nextMessage = nil + if s.closeForShutdownErr != nil { + return read, s.closeForShutdownErr + } + switch s.receiveState { + case receiveStateDataRead: + return read, io.EOF + case receiveStateReset: + return read, network.ErrReset + } + } +} + +func (s *stream) SetReadDeadline(t time.Time) error { + s.mx.Lock() + defer s.mx.Unlock() + if s.receiveState == receiveStateReceiving { + s.setDataChannelReadDeadline(t) + } + return nil +} + +func (s *stream) setDataChannelReadDeadline(t time.Time) error { + return s.dataChannel.SetReadDeadline(t) +} + +func (s *stream) CloseRead() error { + s.mx.Lock() + defer s.mx.Unlock() + var err error + if s.receiveState == receiveStateReceiving && s.closeForShutdownErr == nil { + err = s.writer.WriteMsg(&pb.Message{Flag: pb.Message_STOP_SENDING.Enum()}) + s.receiveState = receiveStateReset + } + s.spawnControlMessageReader() + return err +} diff --git a/go-libp2p/p2p/transport/webrtc/stream_test.go b/go-libp2p/p2p/transport/webrtc/stream_test.go new file mode 100644 index 0000000..0f57f44 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/stream_test.go @@ -0,0 +1,563 @@ +package libp2pwebrtc + +import ( + "crypto/rand" + "errors" + "io" + "os" + "sync/atomic" + "testing" + "time" + + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb" + "github.com/libp2p/go-msgio/pbio" + "google.golang.org/protobuf/proto" + + "github.com/libp2p/go-libp2p/core/network" + + "github.com/pion/datachannel" + "github.com/pion/sctp" + "github.com/pion/webrtc/v3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type detachedChan struct { + rwc datachannel.ReadWriteCloser + dc *webrtc.DataChannel +} + +func getDetachedDataChannels(t *testing.T) (detachedChan, detachedChan) { + s := webrtc.SettingEngine{} + s.SetIncludeLoopbackCandidate(true) + s.DetachDataChannels() + api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) + + offerPC, err := api.NewPeerConnection(webrtc.Configuration{}) + require.NoError(t, err) + t.Cleanup(func() { offerPC.Close() }) + offerRWCChan := make(chan detachedChan, 1) + offerDC, err := offerPC.CreateDataChannel("data", nil) + require.NoError(t, err) + offerDC.OnOpen(func() { + rwc, err := offerDC.Detach() + require.NoError(t, err) + offerRWCChan <- detachedChan{rwc: rwc, dc: offerDC} + }) + + answerPC, err := api.NewPeerConnection(webrtc.Configuration{}) + require.NoError(t, err) + + answerChan := make(chan detachedChan, 1) + answerPC.OnDataChannel(func(dc *webrtc.DataChannel) { + dc.OnOpen(func() { + rwc, err := dc.Detach() + require.NoError(t, err) + answerChan <- detachedChan{rwc: rwc, dc: dc} + }) + }) + t.Cleanup(func() { answerPC.Close() }) + + // Set ICE Candidate handlers. As soon as a PeerConnection has gathered a candidate send it to the other peer + answerPC.OnICECandidate(func(candidate *webrtc.ICECandidate) { + if candidate != nil { + require.NoError(t, offerPC.AddICECandidate(candidate.ToJSON())) + } + }) + offerPC.OnICECandidate(func(candidate *webrtc.ICECandidate) { + if candidate != nil { + require.NoError(t, answerPC.AddICECandidate(candidate.ToJSON())) + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + offerPC.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + if s == webrtc.PeerConnectionStateFailed { + t.Log("peer connection failed on offerer") + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + answerPC.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + if s == webrtc.PeerConnectionStateFailed { + t.Log("peer connection failed on answerer") + } + }) + + // Now, create an offer + offer, err := offerPC.CreateOffer(nil) + require.NoError(t, err) + require.NoError(t, answerPC.SetRemoteDescription(offer)) + require.NoError(t, offerPC.SetLocalDescription(offer)) + + answer, err := answerPC.CreateAnswer(nil) + require.NoError(t, err) + require.NoError(t, offerPC.SetRemoteDescription(answer)) + require.NoError(t, answerPC.SetLocalDescription(answer)) + + return <-answerChan, <-offerRWCChan +} + +// assertDataChannelOpen checks if the datachannel is open. +// It sends empty messages on the data channel to check if the channel is still open. +// The control message reader goroutine depends on exclusive access to datachannel.Read +// so we have to depend on Write to determine whether the channel has been closed. +func assertDataChannelOpen(t *testing.T, dc *datachannel.DataChannel) { + t.Helper() + emptyMsg := &pb.Message{} + msg, err := proto.Marshal(emptyMsg) + if err != nil { + t.Fatal("unexpected mashalling error", err) + } + for i := 0; i < 3; i++ { + _, err := dc.Write(msg) + if err != nil { + t.Fatal("unexpected write err: ", err) + } + time.Sleep(50 * time.Millisecond) + } +} + +// assertDataChannelClosed checks if the datachannel is closed. +// It sends empty messages on the data channel to check if the channel has been closed. +// The control message reader goroutine depends on exclusive access to datachannel.Read +// so we have to depend on Write to determine whether the channel has been closed. +func assertDataChannelClosed(t *testing.T, dc *datachannel.DataChannel) { + t.Helper() + emptyMsg := &pb.Message{} + msg, err := proto.Marshal(emptyMsg) + if err != nil { + t.Fatal("unexpected mashalling error", err) + } + for i := 0; i < 5; i++ { + _, err := dc.Write(msg) + if err != nil { + if errors.Is(err, sctp.ErrStreamClosed) { + return + } else { + t.Fatal("unexpected write err: ", err) + } + } + time.Sleep(50 * time.Millisecond) + } +} + +func TestStreamSimpleReadWriteClose(t *testing.T) { + client, server := getDetachedDataChannels(t) + + var clientDone, serverDone atomic.Bool + clientStr := newStream(client.dc, client.rwc, func() { clientDone.Store(true) }) + serverStr := newStream(server.dc, server.rwc, func() { serverDone.Store(true) }) + + // send a foobar from the client + n, err := clientStr.Write([]byte("foobar")) + require.NoError(t, err) + require.Equal(t, 6, n) + require.NoError(t, clientStr.CloseWrite()) + // writing after closing should error + _, err = clientStr.Write([]byte("foobar")) + require.Error(t, err) + require.False(t, clientDone.Load()) + + // now read all the data on the server side + b, err := io.ReadAll(serverStr) + require.NoError(t, err) + require.Equal(t, []byte("foobar"), b) + // reading again should give another io.EOF + n, err = serverStr.Read(make([]byte, 10)) + require.Zero(t, n) + require.ErrorIs(t, err, io.EOF) + require.False(t, serverDone.Load()) + + // send something back + _, err = serverStr.Write([]byte("lorem ipsum")) + require.NoError(t, err) + require.NoError(t, serverStr.CloseWrite()) + + // and read it at the client + require.False(t, clientDone.Load()) + b, err = io.ReadAll(clientStr) + require.NoError(t, err) + require.Equal(t, []byte("lorem ipsum"), b) + + // stream is only cleaned up on calling Close or Reset + clientStr.Close() + serverStr.Close() + require.Eventually(t, func() bool { return clientDone.Load() }, 5*time.Second, 100*time.Millisecond) + // Need to call Close for cleanup. Otherwise the FIN_ACK is never read + require.NoError(t, serverStr.Close()) + require.Eventually(t, func() bool { return serverDone.Load() }, 5*time.Second, 100*time.Millisecond) +} + +func TestStreamPartialReads(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + + _, err := serverStr.Write([]byte("foobar")) + require.NoError(t, err) + require.NoError(t, serverStr.CloseWrite()) + + n, err := clientStr.Read([]byte{}) // empty read + require.NoError(t, err) + require.Zero(t, n) + b := make([]byte, 3) + n, err = clientStr.Read(b) + require.Equal(t, 3, n) + require.NoError(t, err) + require.Equal(t, []byte("foo"), b) + b, err = io.ReadAll(clientStr) + require.NoError(t, err) + require.Equal(t, []byte("bar"), b) +} + +func TestStreamSkipEmptyFrames(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + + for i := 0; i < 10; i++ { + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{})) + } + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{Message: []byte("foo")})) + for i := 0; i < 10; i++ { + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{})) + } + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{Message: []byte("bar")})) + for i := 0; i < 10; i++ { + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{})) + } + require.NoError(t, serverStr.writer.WriteMsg(&pb.Message{Flag: pb.Message_FIN.Enum()})) + + var read []byte + var count int + for i := 0; i < 100; i++ { + b := make([]byte, 10) + count++ + n, err := clientStr.Read(b) + read = append(read, b[:n]...) + if err == io.EOF { + break + } + require.NoError(t, err) + } + require.LessOrEqual(t, count, 3, "should've taken a maximum of 3 reads") + require.Equal(t, []byte("foobar"), read) +} + +func TestStreamReadReturnsOnClose(t *testing.T) { + client, _ := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + errChan := make(chan error, 1) + go func() { + _, err := clientStr.Read([]byte{0}) + errChan <- err + }() + time.Sleep(100 * time.Millisecond) // give the Read call some time to hit the loop + require.NoError(t, clientStr.Close()) + select { + case err := <-errChan: + require.ErrorIs(t, err, network.ErrReset) + case <-time.After(500 * time.Millisecond): + t.Fatal("timeout") + } + + _, err := clientStr.Read([]byte{0}) + require.ErrorIs(t, err, network.ErrReset) +} + +func TestStreamResets(t *testing.T) { + client, server := getDetachedDataChannels(t) + + var clientDone, serverDone atomic.Bool + clientStr := newStream(client.dc, client.rwc, func() { clientDone.Store(true) }) + serverStr := newStream(server.dc, server.rwc, func() { serverDone.Store(true) }) + + // send a foobar from the client + _, err := clientStr.Write([]byte("foobar")) + require.NoError(t, err) + _, err = serverStr.Write([]byte("lorem ipsum")) + require.NoError(t, err) + require.NoError(t, clientStr.Reset()) // resetting resets both directions + require.True(t, clientDone.Load()) + // attempting to write more data should result in a reset error + _, err = clientStr.Write([]byte("foobar")) + require.ErrorIs(t, err, network.ErrReset) + // read what the server sent + b, err := io.ReadAll(clientStr) + require.Empty(t, b) + require.ErrorIs(t, err, network.ErrReset) + + // read the data on the server side + require.False(t, serverDone.Load()) + b, err = io.ReadAll(serverStr) + require.Equal(t, []byte("foobar"), b) + require.ErrorIs(t, err, network.ErrReset) + require.Eventually(t, func() bool { + _, err := serverStr.Write([]byte("foobar")) + return errors.Is(err, network.ErrReset) + }, time.Second, 50*time.Millisecond) + serverStr.Close() + require.Eventually(t, func() bool { + return serverDone.Load() + }, time.Second, 50*time.Millisecond) +} + +func TestStreamReadDeadlineAsync(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + + timeout := 100 * time.Millisecond + if os.Getenv("CI") != "" { + timeout *= 5 + } + start := time.Now() + clientStr.SetReadDeadline(start.Add(timeout)) + _, err := clientStr.Read([]byte{0}) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + took := time.Since(start) + require.GreaterOrEqual(t, took, timeout) + require.LessOrEqual(t, took, timeout*3/2) + // repeated calls should return immediately + start = time.Now() + _, err = clientStr.Read([]byte{0}) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + require.LessOrEqual(t, time.Since(start), timeout/3) + // clear the deadline + clientStr.SetReadDeadline(time.Time{}) + _, err = serverStr.Write([]byte("foobar")) + require.NoError(t, err) + _, err = clientStr.Read([]byte{0}) + require.NoError(t, err) + require.LessOrEqual(t, time.Since(start), timeout/3) +} + +func TestStreamWriteDeadlineAsync(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + _ = serverStr + + b := make([]byte, 1024) + rand.Read(b) + start := time.Now() + timeout := 100 * time.Millisecond + if os.Getenv("CI") != "" { + timeout *= 5 + } + clientStr.SetWriteDeadline(start.Add(timeout)) + var hitDeadline bool + for i := 0; i < 2000; i++ { + if _, err := clientStr.Write(b); err != nil { + t.Logf("wrote %d kB", i) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + hitDeadline = true + break + } + } + require.True(t, hitDeadline) + took := time.Since(start) + require.GreaterOrEqual(t, took, timeout) + require.LessOrEqual(t, took, timeout*3/2) +} + +func TestStreamReadAfterClose(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + + serverStr.Close() + b := make([]byte, 1) + _, err := clientStr.Read(b) + require.Equal(t, io.EOF, err) + _, err = clientStr.Read(nil) + require.Equal(t, io.EOF, err) + + client, server = getDetachedDataChannels(t) + + clientStr = newStream(client.dc, client.rwc, func() {}) + serverStr = newStream(server.dc, server.rwc, func() {}) + + serverStr.Reset() + b = make([]byte, 1) + _, err = clientStr.Read(b) + require.ErrorIs(t, err, network.ErrReset) + _, err = clientStr.Read(nil) + require.ErrorIs(t, err, network.ErrReset) +} + +func TestStreamCloseAfterFINACK(t *testing.T) { + client, server := getDetachedDataChannels(t) + + done := make(chan bool, 1) + clientStr := newStream(client.dc, client.rwc, func() { done <- true }) + serverStr := newStream(server.dc, server.rwc, func() {}) + + go func() { + err := clientStr.Close() + assert.NoError(t, err) + }() + + select { + case <-done: + case <-time.After(200 * time.Millisecond): + t.Fatalf("Close should signal OnDone immediately") + } + + // Reading FIN_ACK on server should trigger data channel close on the client + b := make([]byte, 1) + _, err := serverStr.Read(b) + require.Error(t, err) + require.ErrorIs(t, err, io.EOF) + assertDataChannelClosed(t, client.rwc.(*datachannel.DataChannel)) +} + +// TestStreamFinAckAfterStopSending tests that FIN_ACK is sent even after the write half +// of the stream is closed. +func TestStreamFinAckAfterStopSending(t *testing.T) { + client, server := getDetachedDataChannels(t) + + done := make(chan bool, 1) + clientStr := newStream(client.dc, client.rwc, func() { done <- true }) + serverStr := newStream(server.dc, server.rwc, func() {}) + + go func() { + clientStr.CloseRead() + clientStr.Write([]byte("hello world")) + done <- true + err := clientStr.Close() + assert.NoError(t, err) + }() + <-done + + select { + case <-done: + case <-time.After(500 * time.Millisecond): + t.Errorf("Close should signal onDone immediately") + } + + // serverStr has write half closed and read half open + // serverStr should still send FIN_ACK + b := make([]byte, 24) + _, err := serverStr.Read(b) + require.NoError(t, err) + serverStr.Close() // Sends stop_sending, fin + assertDataChannelClosed(t, server.rwc.(*datachannel.DataChannel)) + assertDataChannelClosed(t, client.rwc.(*datachannel.DataChannel)) +} + +func TestStreamConcurrentClose(t *testing.T) { + client, server := getDetachedDataChannels(t) + + start := make(chan bool, 2) + done := make(chan bool, 2) + clientStr := newStream(client.dc, client.rwc, func() { done <- true }) + serverStr := newStream(server.dc, server.rwc, func() { done <- true }) + + go func() { + start <- true + clientStr.Close() + }() + go func() { + start <- true + serverStr.Close() + }() + <-start + <-start + + select { + case <-done: + case <-time.After(2 * time.Second): + t.Fatalf("concurrent close should succeed quickly") + } + select { + case <-done: + case <-time.After(2 * time.Second): + t.Fatalf("concurrent close should succeed quickly") + } + + // Wait for FIN_ACK AND datachannel close + assertDataChannelClosed(t, client.rwc.(*datachannel.DataChannel)) + assertDataChannelClosed(t, server.rwc.(*datachannel.DataChannel)) + +} + +func TestStreamResetAfterClose(t *testing.T) { + client, server := getDetachedDataChannels(t) + + done := make(chan bool, 2) + clientStr := newStream(client.dc, client.rwc, func() { done <- true }) + clientStr.Close() + + select { + case <-done: + case <-time.After(500 * time.Millisecond): + t.Fatalf("Close should run cleanup immediately") + } + // The server data channel should still be open + assertDataChannelOpen(t, server.rwc.(*datachannel.DataChannel)) + clientStr.Reset() + // Reset closes the datachannels + assertDataChannelClosed(t, server.rwc.(*datachannel.DataChannel)) + assertDataChannelClosed(t, client.rwc.(*datachannel.DataChannel)) + select { + case <-done: + t.Fatalf("onDone should not be called twice") + case <-time.After(50 * time.Millisecond): + } +} + +func TestStreamDataChannelCloseOnFINACK(t *testing.T) { + client, server := getDetachedDataChannels(t) + + done := make(chan bool, 1) + clientStr := newStream(client.dc, client.rwc, func() { done <- true }) + + clientStr.Close() + + select { + case <-time.After(500 * time.Millisecond): + t.Fatalf("Close should run cleanup immediately") + case <-done: + } + + // sending FIN_ACK closes the datachannel + serverWriter := pbio.NewDelimitedWriter(server.rwc) + err := serverWriter.WriteMsg(&pb.Message{Flag: pb.Message_FIN_ACK.Enum()}) + require.NoError(t, err) + + assertDataChannelClosed(t, server.rwc.(*datachannel.DataChannel)) + assertDataChannelClosed(t, client.rwc.(*datachannel.DataChannel)) +} + +func TestStreamChunking(t *testing.T) { + client, server := getDetachedDataChannels(t) + + clientStr := newStream(client.dc, client.rwc, func() {}) + serverStr := newStream(server.dc, server.rwc, func() {}) + + const N = (16 << 10) + 1000 + go func() { + data := make([]byte, N) + _, err := clientStr.Write(data) + require.NoError(t, err) + }() + + data := make([]byte, N) + n, err := serverStr.Read(data) + require.NoError(t, err) + require.LessOrEqual(t, n, 16<<10) + + nn, err := serverStr.Read(data) + require.NoError(t, err) + require.Equal(t, nn+n, N) +} diff --git a/go-libp2p/p2p/transport/webrtc/stream_write.go b/go-libp2p/p2p/transport/webrtc/stream_write.go new file mode 100644 index 0000000..534a8d8 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/stream_write.go @@ -0,0 +1,157 @@ +package libp2pwebrtc + +import ( + "errors" + "os" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb" +) + +var errWriteAfterClose = errors.New("write after close") + +// If we have less space than minMessageSize, we don't put a new message on the data channel. +// Instead, we wait until more space opens up. +const minMessageSize = 1 << 10 + +func (s *stream) Write(b []byte) (int, error) { + s.mx.Lock() + defer s.mx.Unlock() + + if s.closeForShutdownErr != nil { + return 0, s.closeForShutdownErr + } + switch s.sendState { + case sendStateReset: + return 0, network.ErrReset + case sendStateDataSent, sendStateDataReceived: + return 0, errWriteAfterClose + } + + if !s.writeDeadline.IsZero() && time.Now().After(s.writeDeadline) { + return 0, os.ErrDeadlineExceeded + } + + var writeDeadlineTimer *time.Timer + defer func() { + if writeDeadlineTimer != nil { + writeDeadlineTimer.Stop() + } + }() + + var n int + var msg pb.Message + for len(b) > 0 { + if s.closeForShutdownErr != nil { + return n, s.closeForShutdownErr + } + switch s.sendState { + case sendStateReset: + return n, network.ErrReset + case sendStateDataSent, sendStateDataReceived: + return n, errWriteAfterClose + } + + writeDeadline := s.writeDeadline + // deadline deleted, stop and remove the timer + if writeDeadline.IsZero() && writeDeadlineTimer != nil { + writeDeadlineTimer.Stop() + writeDeadlineTimer = nil + } + var writeDeadlineChan <-chan time.Time + if !writeDeadline.IsZero() { + if writeDeadlineTimer == nil { + writeDeadlineTimer = time.NewTimer(time.Until(writeDeadline)) + } else { + if !writeDeadlineTimer.Stop() { + <-writeDeadlineTimer.C + } + writeDeadlineTimer.Reset(time.Until(writeDeadline)) + } + writeDeadlineChan = writeDeadlineTimer.C + } + + availableSpace := s.availableSendSpace() + if availableSpace < minMessageSize { + s.mx.Unlock() + select { + case <-writeDeadlineChan: + s.mx.Lock() + return n, os.ErrDeadlineExceeded + case <-s.writeStateChanged: + } + s.mx.Lock() + continue + } + end := maxMessageSize + if end > availableSpace { + end = availableSpace + } + end -= protoOverhead + varintOverhead + if end > len(b) { + end = len(b) + } + msg = pb.Message{Message: b[:end]} + if err := s.writer.WriteMsg(&msg); err != nil { + return n, err + } + n += end + b = b[end:] + } + return n, nil +} + +func (s *stream) SetWriteDeadline(t time.Time) error { + s.mx.Lock() + defer s.mx.Unlock() + s.writeDeadline = t + s.notifyWriteStateChanged() + return nil +} + +func (s *stream) availableSendSpace() int { + buffered := int(s.dataChannel.BufferedAmount()) + availableSpace := maxSendBuffer - buffered + if availableSpace+maxTotalControlMessagesSize < 0 { // this should never happen, but better check + log.Errorw("data channel buffered more data than the maximum amount", "max", maxSendBuffer, "buffered", buffered) + } + return availableSpace +} + +func (s *stream) cancelWrite() error { + s.mx.Lock() + defer s.mx.Unlock() + + // There's no need to reset the write half if the write half has been closed + // successfully or has been reset previously + if s.sendState == sendStateDataReceived || s.sendState == sendStateReset { + return nil + } + s.sendState = sendStateReset + // Remove reference to this stream from data channel + s.dataChannel.OnBufferedAmountLow(nil) + s.notifyWriteStateChanged() + return s.writer.WriteMsg(&pb.Message{Flag: pb.Message_RESET.Enum()}) +} + +func (s *stream) CloseWrite() error { + s.mx.Lock() + defer s.mx.Unlock() + + if s.sendState != sendStateSending { + return nil + } + s.sendState = sendStateDataSent + // Remove reference to this stream from data channel + s.dataChannel.OnBufferedAmountLow(nil) + s.notifyWriteStateChanged() + return s.writer.WriteMsg(&pb.Message{Flag: pb.Message_FIN.Enum()}) +} + +func (s *stream) notifyWriteStateChanged() { + select { + case s.writeStateChanged <- struct{}{}: + default: + } +} diff --git a/go-libp2p/p2p/transport/webrtc/transport.go b/go-libp2p/p2p/transport/webrtc/transport.go new file mode 100644 index 0000000..b04753e --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/transport.go @@ -0,0 +1,651 @@ +// Package libp2pwebrtc implements the WebRTC transport for go-libp2p, +// as described in https://github.com/libp2p/specs/tree/master/webrtc. +// +// At this point, this package is EXPERIMENTAL, and the WebRTC transport is not enabled by default. +// While we're fairly confident that the implementation correctly implements the specification, +// we're not making any guarantees regarding its security (especially regarding resource exhaustion attacks). +// Fixes, even for security-related issues, will be conducted in the open. +// +// Experimentation is encouraged. Please open an issue if you encounter any problems with this transport. +// +// The udpmux subpackage contains the logic for multiplexing multiple WebRTC (ICE) +// connections over a single UDP socket. +package libp2pwebrtc + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/binary" + "errors" + "fmt" + "net" + "time" + + mrand "golang.org/x/exp/rand" + "google.golang.org/protobuf/proto" + + "github.com/libp2p/go-libp2p/core/connmgr" + ic "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/pnet" + "github.com/libp2p/go-libp2p/core/sec" + tpt "github.com/libp2p/go-libp2p/core/transport" + "github.com/libp2p/go-libp2p/p2p/security/noise" + "github.com/libp2p/go-libp2p/p2p/transport/webrtc/pb" + "github.com/libp2p/go-msgio" + + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/multiformats/go-multihash" + + "github.com/pion/datachannel" + "github.com/pion/webrtc/v3" +) + +var webrtcComponent *ma.Component + +func init() { + var err error + webrtcComponent, err = ma.NewComponent(ma.ProtocolWithCode(ma.P_WEBRTC_DIRECT).Name, "") + if err != nil { + log.Fatal(err) + } +} + +const ( + // handshakeChannelNegotiated is used to specify that the + // handshake data channel does not need negotiation via DCEP. + // A constant is used since the `DataChannelInit` struct takes + // references instead of values. + handshakeChannelNegotiated = true + // handshakeChannelID is the agreed ID for the handshake data + // channel. A constant is used since the `DataChannelInit` struct takes + // references instead of values. We specify the type here as this + // value is only ever copied and passed by reference + handshakeChannelID = uint16(0) +) + +// timeout values for the peerconnection +// https://github.com/pion/webrtc/blob/v3.1.50/settingengine.go#L102-L109 +const ( + DefaultDisconnectedTimeout = 20 * time.Second + DefaultFailedTimeout = 30 * time.Second + DefaultKeepaliveTimeout = 15 * time.Second + + sctpReceiveBufferSize = 100_000 +) + +type WebRTCTransport struct { + webrtcConfig webrtc.Configuration + rcmgr network.ResourceManager + gater connmgr.ConnectionGater + privKey ic.PrivKey + noiseTpt *noise.Transport + localPeerId peer.ID + + // timeouts + peerConnectionTimeouts iceTimeouts + + // in-flight connections + maxInFlightConnections uint32 +} + +var _ tpt.Transport = &WebRTCTransport{} + +type Option func(*WebRTCTransport) error + +type iceTimeouts struct { + Disconnect time.Duration + Failed time.Duration + Keepalive time.Duration +} + +func New(privKey ic.PrivKey, psk pnet.PSK, gater connmgr.ConnectionGater, rcmgr network.ResourceManager, opts ...Option) (*WebRTCTransport, error) { + if psk != nil { + log.Error("WebRTC doesn't support private networks yet.") + return nil, fmt.Errorf("WebRTC doesn't support private networks yet") + } + if rcmgr == nil { + rcmgr = &network.NullResourceManager{} + } + localPeerID, err := peer.IDFromPrivateKey(privKey) + if err != nil { + return nil, fmt.Errorf("get local peer ID: %w", err) + } + // We use elliptic P-256 since it is widely supported by browsers. + // + // Implementation note: Testing with the browser, + // it seems like Chromium only supports ECDSA P-256 or RSA key signatures in the webrtc TLS certificate. + // We tried using P-228 and P-384 which caused the DTLS handshake to fail with Illegal Parameter + // + // Please refer to this is a list of suggested algorithms for the WebCrypto API. + // The algorithm for generating a certificate for an RTCPeerConnection + // must adhere to the WebCrpyto API. From my observation, + // RSA and ECDSA P-256 is supported on almost all browsers. + // Ed25519 is not present on the list. + pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, fmt.Errorf("generate key for cert: %w", err) + } + cert, err := webrtc.GenerateCertificate(pk) + if err != nil { + return nil, fmt.Errorf("generate certificate: %w", err) + } + config := webrtc.Configuration{ + Certificates: []webrtc.Certificate{*cert}, + } + noiseTpt, err := noise.New(noise.ID, privKey, nil) + if err != nil { + return nil, fmt.Errorf("unable to create noise transport: %w", err) + } + transport := &WebRTCTransport{ + rcmgr: rcmgr, + gater: gater, + webrtcConfig: config, + privKey: privKey, + noiseTpt: noiseTpt, + localPeerId: localPeerID, + + peerConnectionTimeouts: iceTimeouts{ + Disconnect: DefaultDisconnectedTimeout, + Failed: DefaultFailedTimeout, + Keepalive: DefaultKeepaliveTimeout, + }, + + maxInFlightConnections: DefaultMaxInFlightConnections, + } + for _, opt := range opts { + if err := opt(transport); err != nil { + return nil, err + } + } + return transport, nil +} + +func (t *WebRTCTransport) Protocols() []int { + return []int{ma.P_WEBRTC_DIRECT} +} + +func (t *WebRTCTransport) Proxy() bool { + return false +} + +func (t *WebRTCTransport) CanDial(addr ma.Multiaddr) bool { + isValid, n := IsWebRTCDirectMultiaddr(addr) + return isValid && n > 0 +} + +// Listen returns a listener for addr. +// +// The IP, Port combination for addr must be exclusive to this listener as a WebRTC listener cannot +// be multiplexed on the same port as other UDP based transports like QUIC and WebTransport. +// See https://github.com/libp2p/go-libp2p/issues/2446 for details. +func (t *WebRTCTransport) Listen(addr ma.Multiaddr) (tpt.Listener, error) { + addr, wrtcComponent := ma.SplitLast(addr) + isWebrtc := wrtcComponent.Equal(webrtcComponent) + if !isWebrtc { + return nil, fmt.Errorf("must listen on webrtc multiaddr") + } + nw, host, err := manet.DialArgs(addr) + if err != nil { + return nil, fmt.Errorf("listener could not fetch dialargs: %w", err) + } + udpAddr, err := net.ResolveUDPAddr(nw, host) + if err != nil { + return nil, fmt.Errorf("listener could not resolve udp address: %w", err) + } + + socket, err := net.ListenUDP(nw, udpAddr) + if err != nil { + return nil, fmt.Errorf("listen on udp: %w", err) + } + + listener, err := t.listenSocket(socket) + if err != nil { + socket.Close() + return nil, err + } + return listener, nil +} + +func (t *WebRTCTransport) listenSocket(socket *net.UDPConn) (tpt.Listener, error) { + listenerMultiaddr, err := manet.FromNetAddr(socket.LocalAddr()) + if err != nil { + return nil, err + } + + listenerFingerprint, err := t.getCertificateFingerprint() + if err != nil { + return nil, err + } + + encodedLocalFingerprint, err := encodeDTLSFingerprint(listenerFingerprint) + if err != nil { + return nil, err + } + + certComp, err := ma.NewComponent(ma.ProtocolWithCode(ma.P_CERTHASH).Name, encodedLocalFingerprint) + if err != nil { + return nil, err + } + listenerMultiaddr = listenerMultiaddr.Encapsulate(webrtcComponent).Encapsulate(certComp) + + return newListener( + t, + listenerMultiaddr, + socket, + t.webrtcConfig, + ) +} + +func (t *WebRTCTransport) Dial(ctx context.Context, remoteMultiaddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) { + scope, err := t.rcmgr.OpenConnection(network.DirOutbound, false, remoteMultiaddr) + if err != nil { + return nil, err + } + if err := scope.SetPeer(p); err != nil { + scope.Done() + return nil, err + } + conn, err := t.dial(ctx, scope, remoteMultiaddr, p) + if err != nil { + scope.Done() + return nil, err + } + return conn, nil +} + +func (t *WebRTCTransport) dial(ctx context.Context, scope network.ConnManagementScope, remoteMultiaddr ma.Multiaddr, p peer.ID) (tConn tpt.CapableConn, err error) { + var w webRTCConnection + defer func() { + if err != nil { + if w.PeerConnection != nil { + _ = w.PeerConnection.Close() + } + if tConn != nil { + _ = tConn.Close() + } + } + }() + + remoteMultihash, err := decodeRemoteFingerprint(remoteMultiaddr) + if err != nil { + return nil, fmt.Errorf("decode fingerprint: %w", err) + } + remoteHashFunction, ok := getSupportedSDPHash(remoteMultihash.Code) + if !ok { + return nil, fmt.Errorf("unsupported hash function: %w", nil) + } + + rnw, rhost, err := manet.DialArgs(remoteMultiaddr) + if err != nil { + return nil, fmt.Errorf("generate dial args: %w", err) + } + + raddr, err := net.ResolveUDPAddr(rnw, rhost) + if err != nil { + return nil, fmt.Errorf("resolve udp address: %w", err) + } + + // Instead of encoding the local fingerprint we + // generate a random UUID as the connection ufrag. + // The only requirement here is that the ufrag and password + // must be equal, which will allow the server to determine + // the password using the STUN message. + ufrag := genUfrag() + + settingEngine := webrtc.SettingEngine{ + LoggerFactory: pionLoggerFactory, + } + settingEngine.SetICECredentials(ufrag, ufrag) + settingEngine.DetachDataChannels() + // use the first best address candidate + settingEngine.SetPrflxAcceptanceMinWait(0) + settingEngine.SetICETimeouts( + t.peerConnectionTimeouts.Disconnect, + t.peerConnectionTimeouts.Failed, + t.peerConnectionTimeouts.Keepalive, + ) + // By default, webrtc will not collect candidates on the loopback address. + // This is disallowed in the ICE specification. However, implementations + // do not strictly follow this, for eg. Chrome gathers TCP loopback candidates. + // If you run pion on a system with only the loopback interface UP, + // it will not connect to anything. + settingEngine.SetIncludeLoopbackCandidate(true) + settingEngine.SetSCTPMaxReceiveBufferSize(sctpReceiveBufferSize) + if err := scope.ReserveMemory(sctpReceiveBufferSize, network.ReservationPriorityMedium); err != nil { + return nil, err + } + + w, err = newWebRTCConnection(settingEngine, t.webrtcConfig) + if err != nil { + return nil, fmt.Errorf("instantiating peer connection failed: %w", err) + } + + errC := addOnConnectionStateChangeCallback(w.PeerConnection) + + // do offer-answer exchange + offer, err := w.PeerConnection.CreateOffer(nil) + if err != nil { + return nil, fmt.Errorf("create offer: %w", err) + } + + err = w.PeerConnection.SetLocalDescription(offer) + if err != nil { + return nil, fmt.Errorf("set local description: %w", err) + } + + answerSDPString, err := createServerSDP(raddr, ufrag, *remoteMultihash) + if err != nil { + return nil, fmt.Errorf("render server SDP: %w", err) + } + + answer := webrtc.SessionDescription{SDP: answerSDPString, Type: webrtc.SDPTypeAnswer} + err = w.PeerConnection.SetRemoteDescription(answer) + if err != nil { + return nil, fmt.Errorf("set remote description: %w", err) + } + + // await peerconnection opening + select { + case err := <-errC: + if err != nil { + return nil, err + } + case <-ctx.Done(): + return nil, errors.New("peerconnection opening timed out") + } + + // We are connected, run the noise handshake + detached, err := detachHandshakeDataChannel(ctx, w.HandshakeDataChannel) + if err != nil { + return nil, err + } + channel := newStream(w.HandshakeDataChannel, detached, func() {}) + + remotePubKey, err := t.noiseHandshake(ctx, w.PeerConnection, channel, p, remoteHashFunction, false) + if err != nil { + return nil, err + } + + // Setup local and remote address for the connection + cp, err := w.HandshakeDataChannel.Transport().Transport().ICETransport().GetSelectedCandidatePair() + if cp == nil { + return nil, errors.New("ice connection did not have selected candidate pair: nil result") + } + if err != nil { + return nil, fmt.Errorf("ice connection did not have selected candidate pair: error: %w", err) + } + // the local address of the selected candidate pair should be the local address for the connection + localAddr, err := manet.FromNetAddr(&net.UDPAddr{IP: net.ParseIP(cp.Local.Address), Port: int(cp.Local.Port)}) + if err != nil { + return nil, err + } + remoteMultiaddrWithoutCerthash, _ := ma.SplitFunc(remoteMultiaddr, func(c ma.Component) bool { return c.Protocol().Code == ma.P_CERTHASH }) + + conn, err := newConnection( + network.DirOutbound, + w.PeerConnection, + t, + scope, + t.localPeerId, + localAddr, + p, + remotePubKey, + remoteMultiaddrWithoutCerthash, + w.IncomingDataChannels, + ) + if err != nil { + return nil, err + } + + if t.gater != nil && !t.gater.InterceptSecured(network.DirOutbound, p, conn) { + return nil, fmt.Errorf("secured connection gated") + } + return conn, nil +} + +func genUfrag() string { + const ( + uFragAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + uFragPrefix = "libp2p+webrtc+v1/" + uFragIdLength = 32 + uFragIdOffset = len(uFragPrefix) + uFragLength = uFragIdOffset + uFragIdLength + ) + + seed := [8]byte{} + rand.Read(seed[:]) + r := mrand.New(mrand.NewSource(binary.BigEndian.Uint64(seed[:]))) + b := make([]byte, uFragLength) + for i := uFragIdOffset; i < uFragLength; i++ { + b[i] = uFragAlphabet[r.Intn(len(uFragAlphabet))] + } + return string(b) +} + +func (t *WebRTCTransport) getCertificateFingerprint() (webrtc.DTLSFingerprint, error) { + fps, err := t.webrtcConfig.Certificates[0].GetFingerprints() + if err != nil { + return webrtc.DTLSFingerprint{}, err + } + return fps[0], nil +} + +func (t *WebRTCTransport) generateNoisePrologue(pc *webrtc.PeerConnection, hash crypto.Hash, inbound bool) ([]byte, error) { + raw := pc.SCTP().Transport().GetRemoteCertificate() + cert, err := x509.ParseCertificate(raw) + if err != nil { + return nil, err + } + + // NOTE: should we want we can fork the cert code as well to avoid + // all the extra allocations due to unneeded string interspersing (hex) + localFp, err := t.getCertificateFingerprint() + if err != nil { + return nil, err + } + + remoteFpBytes, err := parseFingerprint(cert, hash) + if err != nil { + return nil, err + } + + localFpBytes, err := decodeInterspersedHexFromASCIIString(localFp.Value) + if err != nil { + return nil, err + } + + localEncoded, err := multihash.Encode(localFpBytes, multihash.SHA2_256) + if err != nil { + log.Debugf("could not encode multihash for local fingerprint") + return nil, err + } + remoteEncoded, err := multihash.Encode(remoteFpBytes, multihash.SHA2_256) + if err != nil { + log.Debugf("could not encode multihash for remote fingerprint") + return nil, err + } + + result := []byte("libp2p-webrtc-noise:") + if inbound { + result = append(result, remoteEncoded...) + result = append(result, localEncoded...) + } else { + result = append(result, localEncoded...) + result = append(result, remoteEncoded...) + } + return result, nil +} + +func (t *WebRTCTransport) noiseHandshake(ctx context.Context, pc *webrtc.PeerConnection, s *stream, peer peer.ID, hash crypto.Hash, inbound bool) (ic.PubKey, error) { + prologue, err := t.generateNoisePrologue(pc, hash, inbound) + if err != nil { + return nil, fmt.Errorf("generate prologue: %w", err) + } + opts := make([]noise.SessionOption, 0, 2) + opts = append(opts, noise.Prologue(prologue)) + if peer == "" { + opts = append(opts, noise.DisablePeerIDCheck()) + } + sessionTransport, err := t.noiseTpt.WithSessionOptions(opts...) + if err != nil { + return nil, fmt.Errorf("failed to instantiate Noise transport: %w", err) + } + var secureConn sec.SecureConn + if inbound { + secureConn, err = sessionTransport.SecureOutbound(ctx, netConnWrapper{s}, peer) + if err != nil { + return nil, fmt.Errorf("failed to secure inbound connection: %w", err) + } + } else { + secureConn, err = sessionTransport.SecureInbound(ctx, netConnWrapper{s}, peer) + if err != nil { + return nil, fmt.Errorf("failed to secure outbound connection: %w", err) + } + } + return secureConn.RemotePublicKey(), nil +} + +func (t *WebRTCTransport) AddCertHashes(addr ma.Multiaddr) (ma.Multiaddr, bool) { + listenerFingerprint, err := t.getCertificateFingerprint() + if err != nil { + return nil, false + } + + encodedLocalFingerprint, err := encodeDTLSFingerprint(listenerFingerprint) + if err != nil { + return nil, false + } + + certComp, err := ma.NewComponent(ma.ProtocolWithCode(ma.P_CERTHASH).Name, encodedLocalFingerprint) + if err != nil { + return nil, false + } + return addr.Encapsulate(certComp), true +} + +type netConnWrapper struct { + *stream +} + +func (netConnWrapper) LocalAddr() net.Addr { return nil } +func (netConnWrapper) RemoteAddr() net.Addr { return nil } +func (w netConnWrapper) Close() error { + // Close called while running the security handshake is an error and we should Reset the + // stream in that case rather than gracefully closing + w.stream.Reset() + return nil +} + +// detachHandshakeDataChannel detaches the handshake data channel +func detachHandshakeDataChannel(ctx context.Context, dc *webrtc.DataChannel) (datachannel.ReadWriteCloser, error) { + done := make(chan struct{}) + var rwc datachannel.ReadWriteCloser + var err error + dc.OnOpen(func() { + defer close(done) + rwc, err = dc.Detach() + }) + // this is safe since for detached datachannels, the peerconnection runs the onOpen + // callback immediately if the SCTP transport is also connected. + select { + case <-done: + return rwc, err + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +// webRTCConnection holds the webrtc.PeerConnection with the handshake channel and the queue for +// incoming data channels created by the peer. +// +// When creating a webrtc.PeerConnection, It is important to set the OnDataChannel handler upfront +// before connecting with the peer. If the handler's set up after connecting with the peer, there's +// a small window of time where datachannels created by the peer may not surface to us and cause a +// memory leak. +type webRTCConnection struct { + PeerConnection *webrtc.PeerConnection + HandshakeDataChannel *webrtc.DataChannel + IncomingDataChannels chan dataChannel +} + +func newWebRTCConnection(settings webrtc.SettingEngine, config webrtc.Configuration) (webRTCConnection, error) { + api := webrtc.NewAPI(webrtc.WithSettingEngine(settings)) + pc, err := api.NewPeerConnection(config) + if err != nil { + return webRTCConnection{}, fmt.Errorf("failed to create peer connection: %w", err) + } + + negotiated, id := handshakeChannelNegotiated, handshakeChannelID + handshakeDataChannel, err := pc.CreateDataChannel("", &webrtc.DataChannelInit{ + Negotiated: &negotiated, + ID: &id, + }) + if err != nil { + pc.Close() + return webRTCConnection{}, fmt.Errorf("failed to create handshake channel: %w", err) + } + + incomingDataChannels := make(chan dataChannel, maxAcceptQueueLen) + pc.OnDataChannel(func(dc *webrtc.DataChannel) { + dc.OnOpen(func() { + rwc, err := dc.Detach() + if err != nil { + log.Warnf("could not detach datachannel: id: %d", *dc.ID()) + return + } + select { + case incomingDataChannels <- dataChannel{rwc, dc}: + default: + log.Warnf("connection busy, rejecting stream") + b, _ := proto.Marshal(&pb.Message{Flag: pb.Message_RESET.Enum()}) + w := msgio.NewWriter(rwc) + w.WriteMsg(b) + rwc.Close() + } + }) + }) + return webRTCConnection{ + PeerConnection: pc, + HandshakeDataChannel: handshakeDataChannel, + IncomingDataChannels: incomingDataChannels, + }, nil +} + +// IsWebRTCDirectMultiaddr returns whether addr is a /webrtc-direct multiaddr with the count of certhashes +// in addr +func IsWebRTCDirectMultiaddr(addr ma.Multiaddr) (bool, int) { + var foundUDP, foundWebRTC bool + certHashCount := 0 + ma.ForEach(addr, func(c ma.Component) bool { + if !foundUDP { + if c.Protocol().Code == ma.P_UDP { + foundUDP = true + } + return true + } + if !foundWebRTC && foundUDP { + // protocol after udp must be webrtc-direct + if c.Protocol().Code != ma.P_WEBRTC_DIRECT { + return false + } + foundWebRTC = true + return true + } + if foundWebRTC { + if c.Protocol().Code == ma.P_CERTHASH { + certHashCount++ + } else { + return false + } + } + return true + }) + return foundUDP && foundWebRTC, certHashCount +} diff --git a/go-libp2p/p2p/transport/webrtc/transport_test.go b/go-libp2p/p2p/transport/webrtc/transport_test.go new file mode 100644 index 0000000..a3054a8 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/transport_test.go @@ -0,0 +1,862 @@ +package libp2pwebrtc + +import ( + "context" + "crypto/rand" + "encoding/hex" + "fmt" + "io" + "net" + "os" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multihash" + quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/sha3" +) + +func getTransport(t *testing.T, opts ...Option) (*WebRTCTransport, peer.ID) { + t.Helper() + privKey, _, err := crypto.GenerateKeyPair(crypto.Ed25519, -1) + require.NoError(t, err) + rcmgr := &network.NullResourceManager{} + transport, err := New(privKey, nil, nil, rcmgr, opts...) + require.NoError(t, err) + peerID, err := peer.IDFromPrivateKey(privKey) + require.NoError(t, err) + t.Cleanup(func() { rcmgr.Close() }) + return transport, peerID +} + +func TestIsWebRTCDirectMultiaddr(t *testing.T) { + invalid := []string{ + "/ip4/1.2.3.4/tcp/10/", + "/ip6/1::3/udp/100/quic-v1/", + "/ip4/1.2.3.4/udp/1/quic-v1/webrtc-direct", + } + + valid := []struct { + addr string + count int + }{ + { + addr: "/ip4/1.2.3.4/udp/1234/webrtc-direct", + count: 0, + }, + { + addr: "/dns/test.test/udp/1234/webrtc-direct", + count: 0, + }, + { + addr: "/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + count: 1, + }, + { + addr: "/ip6/0:0:0:0:0:0:0:1/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + count: 1, + }, + { + addr: "/dns/test.test/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + count: 1, + }, + { + addr: "/dns/test.test/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7ZGrV4VZ3hpEKTd_zg", + count: 2, + }, + } + + for _, addr := range invalid { + a := ma.StringCast(addr) + isValid, n := IsWebRTCDirectMultiaddr(a) + require.Equal(t, 0, n) + require.False(t, isValid) + } + + for _, tc := range valid { + a := ma.StringCast(tc.addr) + isValid, n := IsWebRTCDirectMultiaddr(a) + require.Equal(t, tc.count, n) + require.True(t, isValid) + } +} + +func TestTransportWebRTC_CanDial(t *testing.T) { + tr, _ := getTransport(t) + invalid := []string{ + "/ip4/1.2.3.4/udp/1234/webrtc-direct", + "/dns/test.test/udp/1234/webrtc-direct", + } + + valid := []string{ + "/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + "/ip6/0:0:0:0:0:0:0:1/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + "/ip6/::1/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + "/dns/test.test/udp/1234/webrtc-direct/certhash/uEiAsGPzpiPGQzSlVHRXrUCT5EkTV7YFrV4VZ3hpEKTd_zg", + } + + for _, addr := range invalid { + a := ma.StringCast(addr) + require.False(t, tr.CanDial(a)) + } + + for _, addr := range valid { + a := ma.StringCast(addr) + require.True(t, tr.CanDial(a), addr) + } +} + +func TestTransportAddCertHasher(t *testing.T) { + tr, _ := getTransport(t) + addrs := []string{ + "/ip4/1.2.3.4/udp/1/webrtc-direct", + "/ip6/1::3/udp/2/webrtc-direct", + } + for _, a := range addrs { + addr, added := tr.AddCertHashes(ma.StringCast(a)) + require.True(t, added) + _, err := addr.ValueForProtocol(ma.P_CERTHASH) + require.NoError(t, err) + require.True(t, strings.HasPrefix(addr.String(), a)) + } +} + +func TestTransportWebRTC_ListenFailsOnNonWebRTCMultiaddr(t *testing.T) { + tr, _ := getTransport(t) + testAddrs := []string{ + "/ip4/0.0.0.0/udp/0", + "/ip4/0.0.0.0/tcp/0/wss", + } + for _, addr := range testAddrs { + listenMultiaddr, err := ma.NewMultiaddr(addr) + require.NoError(t, err) + listener, err := tr.Listen(listenMultiaddr) + require.Error(t, err) + require.Nil(t, listener) + } +} + +// using assert inside goroutines, refer: https://github.com/stretchr/testify/issues/772#issuecomment-945166599 +func TestTransportWebRTC_DialFailsOnUnsupportedHashFunction(t *testing.T) { + tr, _ := getTransport(t) + hash := sha3.New512() + certhash := func() string { + _, err := hash.Write([]byte("test-data")) + require.NoError(t, err) + mh, err := multihash.Encode(hash.Sum([]byte{}), multihash.SHA3_512) + require.NoError(t, err) + certhash, err := multibase.Encode(multibase.Base58BTC, mh) + require.NoError(t, err) + return certhash + }() + testaddr, err := ma.NewMultiaddr("/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/" + certhash) + require.NoError(t, err) + _, err = tr.Dial(context.Background(), testaddr, "") + require.ErrorContains(t, err, "unsupported hash function") +} + +func TestTransportWebRTC_CanListenSingle(t *testing.T) { + tr, listeningPeer := getTransport(t) + tr1, connectingPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + done := make(chan struct{}) + go func() { + _, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + assert.NoError(t, err) + close(done) + }() + + conn, err := listener.Accept() + require.NoError(t, err) + require.NotNil(t, conn) + + require.Equal(t, connectingPeer, conn.RemotePeer()) + select { + case <-done: + case <-time.After(10 * time.Second): + t.FailNow() + } +} + +// WithListenerMaxInFlightConnections sets the maximum number of connections that are in-flight, i.e +// they are being negotiated, or are waiting to be accepted. +func WithListenerMaxInFlightConnections(m uint32) Option { + return func(t *WebRTCTransport) error { + if m == 0 { + t.maxInFlightConnections = DefaultMaxInFlightConnections + } else { + t.maxInFlightConnections = m + } + return nil + } +} + +func TestTransportWebRTC_CanListenMultiple(t *testing.T) { + count := 3 + tr, listeningPeer := getTransport(t, WithListenerMaxInFlightConnections(uint32(count))) + + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var wg sync.WaitGroup + go func() { + for i := 0; i < count; i++ { + conn, err := listener.Accept() + assert.NoError(t, err) + assert.NotNil(t, conn) + defer conn.Close() + } + wg.Wait() + cancel() + }() + + for i := 0; i < count; i++ { + wg.Add(1) + go func() { + defer wg.Done() + ctr, _ := getTransport(t) + conn, err := ctr.Dial(ctx, listener.Multiaddr(), listeningPeer) + select { + case <-ctx.Done(): + default: + assert.NoError(t, err) + assert.NotNil(t, conn) + t.Cleanup(func() { conn.Close() }) + } + }() + } + + select { + case <-ctx.Done(): + case <-time.After(30 * time.Second): + t.Fatalf("timed out") + } +} + +func TestTransportWebRTC_CanCreateSuccessiveConnections(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + count := 2 + + var wg sync.WaitGroup + wg.Add(count) + go func() { + for i := 0; i < count; i++ { + ctr, _ := getTransport(t) + conn, err := ctr.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + require.Equal(t, conn.RemotePeer(), listeningPeer) + t.Cleanup(func() { conn.Close() }) + wg.Done() + } + }() + + for i := 0; i < count; i++ { + conn, err := listener.Accept() + require.NoError(t, err) + defer conn.Close() + } + wg.Wait() +} + +func TestTransportWebRTC_ListenerCanCreateStreams(t *testing.T) { + tr, listeningPeer := getTransport(t) + tr1, connectingPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + streamChan := make(chan network.MuxedStream) + go func() { + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + t.Cleanup(func() { conn.Close() }) + t.Logf("connection opened by dialer") + + stream, err := conn.AcceptStream() + require.NoError(t, err) + t.Logf("dialer accepted stream") + streamChan <- stream + }() + + conn, err := listener.Accept() + require.NoError(t, err) + defer conn.Close() + require.Equal(t, connectingPeer, conn.RemotePeer()) + t.Logf("listener accepted connection") + + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + t.Logf("listener opened stream") + _, err = stream.Write([]byte("test")) + require.NoError(t, err) + + var str network.MuxedStream + select { + case str = <-streamChan: + case <-time.After(3 * time.Second): + t.Fatal("stream opening timed out") + } + buf := make([]byte, 100) + stream.SetReadDeadline(time.Now().Add(3 * time.Second)) + n, err := str.Read(buf) + require.NoError(t, err) + require.Equal(t, "test", string(buf[:n])) +} + +func TestTransportWebRTC_DialerCanCreateStreams(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, connectingPeer := getTransport(t) + done := make(chan struct{}) + + go func() { + lconn, err := listener.Accept() + require.NoError(t, err) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + defer lconn.Close() + + stream, err := lconn.AcceptStream() + require.NoError(t, err) + buf := make([]byte, 100) + n, err := stream.Read(buf) + require.NoError(t, err) + require.Equal(t, "test", string(buf[:n])) + + close(done) + }() + + go func() { + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + t.Logf("dialer opened connection") + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + t.Logf("dialer opened stream") + _, err = stream.Write([]byte("test")) + require.NoError(t, err) + <-done + }() + + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("timed out") + } +} + +func TestTransportWebRTC_DialerCanCreateStreamsMultiple(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, connectingPeer := getTransport(t) + readerDone := make(chan struct{}) + + const ( + numListeners = 10 + numStreams = 100 + numWriters = 10 + size = 20 << 10 + ) + + go func() { + lconn, err := listener.Accept() + require.NoError(t, err) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + defer lconn.Close() + var wg sync.WaitGroup + var doneStreams atomic.Int32 + for i := 0; i < numListeners; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for { + var nn int32 + if nn = doneStreams.Add(1); nn > int32(numStreams) { + return + } + s, err := lconn.AcceptStream() + require.NoError(t, err) + n, err := io.Copy(s, s) + require.Equal(t, n, int64(size)) + require.NoError(t, err) + s.Close() + } + }() + } + wg.Wait() + readerDone <- struct{}{} + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + + var writerWG sync.WaitGroup + var cnt atomic.Int32 + var streamsStarted atomic.Int32 + for i := 0; i < numWriters; i++ { + writerWG.Add(1) + go func() { + defer writerWG.Done() + buf := make([]byte, size) + for { + var nn int32 + if nn = streamsStarted.Add(1); nn > int32(numStreams) { + return + } + rand.Read(buf) + + s, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + n, err := s.Write(buf) + require.Equal(t, n, size) + require.NoError(t, err) + s.CloseWrite() + resp := make([]byte, size+10) + n, err = io.ReadFull(s, resp) + require.ErrorIs(t, err, io.ErrUnexpectedEOF) + require.Equal(t, n, size) + if string(buf) != string(resp[:size]) { + t.Errorf("bytes not equal: %d %d", len(buf), len(resp)) + } + s.Close() + t.Log("completed stream: ", cnt.Add(1), s.(*stream).id) + } + }() + } + writerWG.Wait() + select { + case <-readerDone: + case <-time.After(100 * time.Second): + t.Fatal("timed out") + } +} + +func TestTransportWebRTC_Deadline(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + tr1, connectingPeer := getTransport(t) + + t.Run("SetReadDeadline", func(t *testing.T) { + go func() { + lconn, err := listener.Accept() + require.NoError(t, err) + t.Cleanup(func() { lconn.Close() }) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + _, err = lconn.AcceptStream() + require.NoError(t, err) + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + + // deadline set to the past + stream.SetReadDeadline(time.Now().Add(-200 * time.Millisecond)) + _, err = stream.Read([]byte{0, 0}) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + + // future deadline exceeded + stream.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + _, err = stream.Read([]byte{0, 0}) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + }) + + t.Run("SetWriteDeadline", func(t *testing.T) { + go func() { + lconn, err := listener.Accept() + require.NoError(t, err) + t.Cleanup(func() { lconn.Close() }) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + _, err = lconn.AcceptStream() + require.NoError(t, err) + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + + stream.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + largeBuffer := make([]byte, 2*1024*1024) + _, err = stream.Write(largeBuffer) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + + stream.SetWriteDeadline(time.Now().Add(-200 * time.Millisecond)) + smallBuffer := make([]byte, 1024) + _, err = stream.Write(smallBuffer) + require.ErrorIs(t, err, os.ErrDeadlineExceeded) + }) +} + +func TestTransportWebRTC_StreamWriteBufferContention(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, connectingPeer := getTransport(t) + + var wg sync.WaitGroup + wg.Add(3) + go func() { + defer wg.Done() + lconn, err := listener.Accept() + require.NoError(t, err) + t.Cleanup(func() { lconn.Close() }) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + for i := 0; i < 2; i++ { + go func() { + defer wg.Done() + _, err := lconn.AcceptStream() + require.NoError(t, err) + }() + } + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + + errC := make(chan error) + // writers + for i := 0; i < 2; i++ { + go func() { + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + + stream.SetWriteDeadline(time.Now().Add(200 * time.Millisecond)) + largeBuffer := make([]byte, 2*1024*1024) + _, err = stream.Write(largeBuffer) + errC <- err + }() + } + + require.ErrorIs(t, <-errC, os.ErrDeadlineExceeded) + require.ErrorIs(t, <-errC, os.ErrDeadlineExceeded) + wg.Wait() +} + +func TestTransportWebRTC_RemoteReadsAfterClose(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, _ := getTransport(t) + + done := make(chan error) + go func() { + lconn, err := listener.Accept() + if err != nil { + done <- err + return + } + t.Cleanup(func() { lconn.Close() }) + + stream, err := lconn.AcceptStream() + if err != nil { + done <- err + return + } + _, err = stream.Write([]byte{1, 2, 3, 4}) + if err != nil { + done <- err + return + } + err = stream.Close() + if err != nil { + done <- err + return + } + close(done) + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + // create a stream + stream, err := conn.OpenStream(context.Background()) + + require.NoError(t, err) + // require write and close to complete + require.NoError(t, <-done) + stream.SetReadDeadline(time.Now().Add(5 * time.Second)) + + buf := make([]byte, 10) + n, err := stream.Read(buf) + require.NoError(t, err) + require.Equal(t, 4, n) +} + +func TestTransportWebRTC_RemoteReadsAfterClose2(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, _ := getTransport(t) + + awaitStreamClosure := make(chan struct{}) + readBytesResult := make(chan int) + done := make(chan error) + go func() { + lconn, err := listener.Accept() + if err != nil { + done <- err + return + } + defer lconn.Close() + stream, err := lconn.AcceptStream() + if err != nil { + done <- err + return + } + + <-awaitStreamClosure + buf := make([]byte, 16) + n, err := stream.Read(buf) + if err != nil { + done <- err + return + } + readBytesResult <- n + close(done) + }() + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + // create a stream + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + _, err = stream.Write([]byte{1, 2, 3, 4}) + require.NoError(t, err) + err = stream.Close() + require.NoError(t, err) + // signal stream closure + close(awaitStreamClosure) + require.Equal(t, 4, <-readBytesResult) +} + +func TestTransportWebRTC_Close(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + listener, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer listener.Close() + + tr1, connectingPeer := getTransport(t) + + t.Run("RemoteClosesStream", func(t *testing.T) { + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + lconn, err := listener.Accept() + require.NoError(t, err) + t.Cleanup(func() { lconn.Close() }) + require.Equal(t, connectingPeer, lconn.RemotePeer()) + stream, err := lconn.AcceptStream() + require.NoError(t, err) + time.Sleep(100 * time.Millisecond) + _ = stream.Close() + }() + + buf := make([]byte, 2) + + conn, err := tr1.Dial(context.Background(), listener.Multiaddr(), listeningPeer) + require.NoError(t, err) + defer conn.Close() + stream, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + + err = stream.SetReadDeadline(time.Now().Add(2 * time.Second)) + require.NoError(t, err) + _, err = stream.Read(buf) + require.ErrorIs(t, err, io.EOF) + + wg.Wait() + }) +} + +func TestTransportWebRTC_PeerConnectionDTLSFailed(t *testing.T) { + tr, listeningPeer := getTransport(t) + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + ln, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer ln.Close() + + encoded, err := hex.DecodeString("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + require.NoError(t, err) + encodedCerthash, err := multihash.Encode(encoded, multihash.SHA2_256) + require.NoError(t, err) + badEncodedCerthash, err := multibase.Encode(multibase.Base58BTC, encodedCerthash) + require.NoError(t, err) + badCerthash, err := ma.NewMultiaddr(fmt.Sprintf("/certhash/%s", badEncodedCerthash)) + require.NoError(t, err) + badMultiaddr, _ := ma.SplitFunc(ln.Multiaddr(), func(c ma.Component) bool { return c.Protocol().Code == ma.P_CERTHASH }) + badMultiaddr = badMultiaddr.Encapsulate(badCerthash) + + tr1, _ := getTransport(t) + conn, err := tr1.Dial(context.Background(), badMultiaddr, listeningPeer) + require.Error(t, err) + require.ErrorContains(t, err, "failed") + require.Nil(t, conn) +} + +func TestConnectionTimeoutOnListener(t *testing.T) { + tr, listeningPeer := getTransport(t) + tr.peerConnectionTimeouts.Disconnect = 100 * time.Millisecond + tr.peerConnectionTimeouts.Failed = 150 * time.Millisecond + tr.peerConnectionTimeouts.Keepalive = 50 * time.Millisecond + + listenMultiaddr := ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct") + ln, err := tr.Listen(listenMultiaddr) + require.NoError(t, err) + defer ln.Close() + + var drop atomic.Bool + proxy, err := quicproxy.NewQuicProxy("127.0.0.1:0", &quicproxy.Opts{ + RemoteAddr: fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.UDPAddr).Port), + DropPacket: func(quicproxy.Direction, []byte) bool { return drop.Load() }, + }) + require.NoError(t, err) + defer proxy.Close() + + tr1, connectingPeer := getTransport(t) + go func() { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + addr, err := manet.FromNetAddr(proxy.LocalAddr()) + require.NoError(t, err) + _, webrtcComponent := ma.SplitFunc(ln.Multiaddr(), func(c ma.Component) bool { return c.Protocol().Code == ma.P_WEBRTC_DIRECT }) + addr = addr.Encapsulate(webrtcComponent) + conn, err := tr1.Dial(ctx, addr, listeningPeer) + require.NoError(t, err) + t.Cleanup(func() { conn.Close() }) + str, err := conn.OpenStream(ctx) + require.NoError(t, err) + str.Write([]byte("foobar")) + }() + + conn, err := ln.Accept() + require.NoError(t, err) + require.Equal(t, connectingPeer, conn.RemotePeer()) + defer conn.Close() + + str, err := conn.AcceptStream() + require.NoError(t, err) + _, err = str.Write([]byte("test")) + require.NoError(t, err) + // start dropping all packets + drop.Store(true) + start := time.Now() + for { + if _, err := str.Write([]byte("test")); err != nil { + if os.IsTimeout(err) { + break + } + // If we write when a connection timeout happens, sctp provides + // a "stream closed" error. This occurs concurrently with the + // callback we receive for connection timeout. + // Test once more after sleep that we provide the correct error. + if strings.Contains(err.Error(), "stream closed") { + time.Sleep(50 * time.Millisecond) + _, err = str.Write([]byte("test")) + require.True(t, os.IsTimeout(err), "invalid error type: %v", err) + } else { + t.Fatal("invalid error type", err) + } + break + } + + if time.Since(start) > 5*time.Second { + t.Fatal("timeout") + } + // make sure to not write too often, we don't want to fill the flow control window + time.Sleep(20 * time.Millisecond) + } + // make sure that accepting a stream also returns an error... + _, err = conn.AcceptStream() + require.True(t, os.IsTimeout(err)) + // ... as well as opening a new stream + _, err = conn.OpenStream(context.Background()) + require.True(t, os.IsTimeout(err)) +} + +func TestMaxInFlightRequests(t *testing.T) { + const count = 3 + tr, listeningPeer := getTransport(t, + WithListenerMaxInFlightConnections(count), + ) + ln, err := tr.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/webrtc-direct")) + require.NoError(t, err) + defer ln.Close() + + var wg sync.WaitGroup + var success, fails atomic.Int32 + for i := 0; i < count+1; i++ { + wg.Add(1) + go func() { + defer wg.Done() + dialer, _ := getTransport(t) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + if conn, err := dialer.Dial(ctx, ln.Multiaddr(), listeningPeer); err == nil { + success.Add(1) + t.Cleanup(func() { conn.Close() }) + } else { + t.Log("failed to dial:", err) + fails.Add(1) + } + }() + } + wg.Wait() + require.Equal(t, count, int(success.Load()), "expected exactly 3 dial successes") + require.Equal(t, 1, int(fails.Load()), "expected exactly 1 dial failure") +} diff --git a/go-libp2p/p2p/transport/webrtc/udpmux/mux.go b/go-libp2p/p2p/transport/webrtc/udpmux/mux.go new file mode 100644 index 0000000..98e60e3 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/udpmux/mux.go @@ -0,0 +1,298 @@ +package udpmux + +import ( + "bytes" + "context" + "fmt" + "io" + "net" + "strings" + "sync" + + logging "github.com/ipfs/go-log/v2" + pool "github.com/libp2p/go-buffer-pool" + "github.com/pion/ice/v2" + "github.com/pion/stun" +) + +var log = logging.Logger("webrtc-udpmux") + +// ReceiveBufSize is the size of the buffer used to receive packets from the PacketConn. +// It is fine for this number to be higher than the actual path MTU as this value is not +// used to decide the packet size on the write path. +const ReceiveBufSize = 1500 + +type Candidate struct { + Ufrag string + Addr *net.UDPAddr +} + +// UDPMux multiplexes multiple ICE connections over a single net.PacketConn, +// generally a UDP socket. +// +// The connections are indexed by (ufrag, IP address family) and by remote +// address from which the connection has received valid STUN/RTC packets. +// +// When a new packet is received on the underlying net.PacketConn, we +// first check the address map to see if there is a connection associated with the +// remote address: +// If found, we pass the packet to that connection. +// Otherwise, we check to see if the packet is a STUN packet. +// If it is, we read the ufrag from the STUN packet and use it to check if there +// is a connection associated with the (ufrag, IP address family) pair. +// If found we add the association to the address map. +type UDPMux struct { + socket net.PacketConn + + queue chan Candidate + + mx sync.Mutex + // ufragMap allows us to multiplex incoming STUN packets based on ufrag + ufragMap map[ufragConnKey]*muxedConnection + // addrMap allows us to correctly direct incoming packets after the connection + // is established and ufrag isn't available on all packets + addrMap map[string]*muxedConnection + // ufragAddrMap allows cleaning up all addresses from the addrMap once the connection is closed + // During the ICE connectivity checks, the same ufrag might be used on multiple addresses. + ufragAddrMap map[ufragConnKey][]net.Addr + + // the context controls the lifecycle of the mux + wg sync.WaitGroup + ctx context.Context + cancel context.CancelFunc +} + +var _ ice.UDPMux = &UDPMux{} + +func NewUDPMux(socket net.PacketConn) *UDPMux { + ctx, cancel := context.WithCancel(context.Background()) + mux := &UDPMux{ + ctx: ctx, + cancel: cancel, + socket: socket, + ufragMap: make(map[ufragConnKey]*muxedConnection), + addrMap: make(map[string]*muxedConnection), + ufragAddrMap: make(map[ufragConnKey][]net.Addr), + queue: make(chan Candidate, 32), + } + + return mux +} + +func (mux *UDPMux) Start() { + mux.wg.Add(1) + go func() { + defer mux.wg.Done() + mux.readLoop() + }() +} + +// GetListenAddresses implements ice.UDPMux +func (mux *UDPMux) GetListenAddresses() []net.Addr { + return []net.Addr{mux.socket.LocalAddr()} +} + +// GetConn implements ice.UDPMux +// It creates a net.PacketConn for a given ufrag if an existing one cannot be found. +// We differentiate IPv4 and IPv6 addresses, since a remote is can be reachable at multiple different +// UDP addresses of the same IP address family (eg. server-reflexive addresses and peer-reflexive addresses). +func (mux *UDPMux) GetConn(ufrag string, addr net.Addr) (net.PacketConn, error) { + a, ok := addr.(*net.UDPAddr) + if !ok { + return nil, fmt.Errorf("unexpected address type: %T", addr) + } + select { + case <-mux.ctx.Done(): + return nil, io.ErrClosedPipe + default: + isIPv6 := ok && a.IP.To4() == nil + _, conn := mux.getOrCreateConn(ufrag, isIPv6, mux, addr) + return conn, nil + } +} + +// Close implements ice.UDPMux +func (mux *UDPMux) Close() error { + select { + case <-mux.ctx.Done(): + return nil + default: + } + mux.cancel() + mux.socket.Close() + mux.wg.Wait() + return nil +} + +// writeTo writes a packet to the underlying net.PacketConn +func (mux *UDPMux) writeTo(buf []byte, addr net.Addr) (int, error) { + return mux.socket.WriteTo(buf, addr) +} + +func (mux *UDPMux) readLoop() { + for { + select { + case <-mux.ctx.Done(): + return + default: + } + + buf := pool.Get(ReceiveBufSize) + + n, addr, err := mux.socket.ReadFrom(buf) + if err != nil { + if strings.Contains(err.Error(), "use of closed network connection") { + log.Debugf("readLoop exiting: socket %s closed", mux.socket.LocalAddr()) + } else { + log.Errorf("error reading from socket %s: %v", mux.socket.LocalAddr(), err) + } + pool.Put(buf) + return + } + buf = buf[:n] + + if processed := mux.processPacket(buf, addr); !processed { + pool.Put(buf) + } + } +} + +func (mux *UDPMux) processPacket(buf []byte, addr net.Addr) (processed bool) { + udpAddr, ok := addr.(*net.UDPAddr) + if !ok { + log.Errorf("received a non-UDP address: %s", addr) + return false + } + isIPv6 := udpAddr.IP.To4() == nil + + // Connections are indexed by remote address. We first + // check if the remote address has a connection associated + // with it. If yes, we push the received packet to the connection + mux.mx.Lock() + conn, ok := mux.addrMap[addr.String()] + mux.mx.Unlock() + if ok { + if err := conn.Push(buf, addr); err != nil { + log.Debugf("could not push packet: %v", err) + return false + } + return true + } + + if !stun.IsMessage(buf) { + log.Debug("incoming message is not a STUN message") + return false + } + + msg := &stun.Message{Raw: buf} + if err := msg.Decode(); err != nil { + log.Debugf("failed to decode STUN message: %s", err) + return false + } + if msg.Type != stun.BindingRequest { + log.Debugf("incoming message should be a STUN binding request, got %s", msg.Type) + return false + } + + ufrag, err := ufragFromSTUNMessage(msg) + if err != nil { + log.Debugf("could not find STUN username: %s", err) + return false + } + + connCreated, conn := mux.getOrCreateConn(ufrag, isIPv6, mux, udpAddr) + if connCreated { + select { + case mux.queue <- Candidate{Addr: udpAddr, Ufrag: ufrag}: + default: + log.Debugw("queue full, dropping incoming candidate", "ufrag", ufrag, "addr", udpAddr) + conn.Close() + return false + } + } + + if err := conn.Push(buf, addr); err != nil { + log.Debugf("could not push packet: %v", err) + return false + } + return true +} + +func (mux *UDPMux) Accept(ctx context.Context) (Candidate, error) { + select { + case c := <-mux.queue: + return c, nil + case <-ctx.Done(): + return Candidate{}, ctx.Err() + case <-mux.ctx.Done(): + return Candidate{}, mux.ctx.Err() + } +} + +type ufragConnKey struct { + ufrag string + isIPv6 bool +} + +// ufragFromSTUNMessage returns the local or ufrag +// from the STUN username attribute. Local ufrag is the ufrag of the +// peer which initiated the connectivity check, e.g in a connectivity +// check from A to B, the username attribute will be B_ufrag:A_ufrag +// with the local ufrag value being A_ufrag. In case of ice-lite, the +// localUfrag value will always be the remote peer's ufrag since ICE-lite +// implementations do not generate connectivity checks. In our specific +// case, since the local and remote ufrag is equal, we can return +// either value. +func ufragFromSTUNMessage(msg *stun.Message) (string, error) { + attr, err := msg.Get(stun.AttrUsername) + if err != nil { + return "", err + } + index := bytes.Index(attr, []byte{':'}) + if index == -1 { + return "", fmt.Errorf("invalid STUN username attribute") + } + return string(attr[index+1:]), nil +} + +// RemoveConnByUfrag removes the connection associated with the ufrag and all the +// addresses associated with that connection. This method is called by pion when +// a peerconnection is closed. +func (mux *UDPMux) RemoveConnByUfrag(ufrag string) { + if ufrag == "" { + return + } + + mux.mx.Lock() + defer mux.mx.Unlock() + + for _, isIPv6 := range [...]bool{true, false} { + key := ufragConnKey{ufrag: ufrag, isIPv6: isIPv6} + if _, ok := mux.ufragMap[key]; ok { + delete(mux.ufragMap, key) + for _, addr := range mux.ufragAddrMap[key] { + delete(mux.addrMap, addr.String()) + } + delete(mux.ufragAddrMap, key) + } + } +} + +func (mux *UDPMux) getOrCreateConn(ufrag string, isIPv6 bool, _ *UDPMux, addr net.Addr) (created bool, _ *muxedConnection) { + key := ufragConnKey{ufrag: ufrag, isIPv6: isIPv6} + + mux.mx.Lock() + defer mux.mx.Unlock() + + if conn, ok := mux.ufragMap[key]; ok { + mux.addrMap[addr.String()] = conn + mux.ufragAddrMap[key] = append(mux.ufragAddrMap[key], addr) + return false, conn + } + + conn := newMuxedConnection(mux, func() { mux.RemoveConnByUfrag(ufrag) }) + mux.ufragMap[key] = conn + mux.addrMap[addr.String()] = conn + mux.ufragAddrMap[key] = append(mux.ufragAddrMap[key], addr) + return true, conn +} diff --git a/go-libp2p/p2p/transport/webrtc/udpmux/mux_test.go b/go-libp2p/p2p/transport/webrtc/udpmux/mux_test.go new file mode 100644 index 0000000..298e5c9 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/udpmux/mux_test.go @@ -0,0 +1,248 @@ +package udpmux + +import ( + "context" + "fmt" + "net" + "testing" + "time" + + "github.com/pion/stun" + "github.com/stretchr/testify/require" +) + +func getSTUNBindingRequest(ufrag string) *stun.Message { + msg := stun.New() + msg.SetType(stun.BindingRequest) + uattr := stun.RawAttribute{ + Type: stun.AttrUsername, + Value: []byte(fmt.Sprintf("%s:%s", ufrag, ufrag)), // This is the format we expect in our connections + } + uattr.AddTo(msg) + msg.Encode() + return msg +} + +func setupMapping(t *testing.T, ufrag string, from net.PacketConn, m *UDPMux) { + t.Helper() + msg := getSTUNBindingRequest(ufrag) + _, err := from.WriteTo(msg.Raw, m.GetListenAddresses()[0]) + require.NoError(t, err) +} + +func newPacketConn(t *testing.T) net.PacketConn { + t.Helper() + udpPort0 := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0} + c, err := net.ListenUDP("udp", udpPort0) + require.NoError(t, err) + t.Cleanup(func() { c.Close() }) + return c +} + +func TestAccept(t *testing.T) { + c := newPacketConn(t) + defer c.Close() + m := NewUDPMux(c) + m.Start() + defer m.Close() + + ufrags := []string{"a", "b", "c", "d"} + conns := make([]net.PacketConn, len(ufrags)) + for i, ufrag := range ufrags { + conns[i] = newPacketConn(t) + setupMapping(t, ufrag, conns[i], m) + } + for i, ufrag := range ufrags { + c, err := m.Accept(context.Background()) + require.NoError(t, err) + require.Equal(t, c.Ufrag, ufrag) + require.Equal(t, c.Addr, conns[i].LocalAddr()) + } + + for i, ufrag := range ufrags { + // should not be accepted + setupMapping(t, ufrag, conns[i], m) + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + _, err := m.Accept(ctx) + require.Error(t, err) + + // should not be accepted + cc := newPacketConn(t) + setupMapping(t, ufrag, cc, m) + ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + _, err = m.Accept(ctx) + require.Error(t, err) + } +} + +func TestGetConn(t *testing.T) { + c := newPacketConn(t) + m := NewUDPMux(c) + m.Start() + defer m.Close() + + ufrags := []string{"a", "b", "c", "d"} + conns := make([]net.PacketConn, len(ufrags)) + for i, ufrag := range ufrags { + conns[i] = newPacketConn(t) + setupMapping(t, ufrag, conns[i], m) + } + for i, ufrag := range ufrags { + c, err := m.Accept(context.Background()) + require.NoError(t, err) + require.Equal(t, c.Ufrag, ufrag) + require.Equal(t, c.Addr, conns[i].LocalAddr()) + } + + for i, ufrag := range ufrags { + c, err := m.GetConn(ufrag, conns[i].LocalAddr()) + require.NoError(t, err) + msg := make([]byte, 100) + _, _, err = c.ReadFrom(msg) + require.NoError(t, err) + } + + for i, ufrag := range ufrags { + cc := newPacketConn(t) + // setupMapping of cc to ufrags[0] and remove the stun binding request from the queue + setupMapping(t, ufrag, cc, m) + mc, err := m.GetConn(ufrag, cc.LocalAddr()) + require.NoError(t, err) + msg := make([]byte, 100) + _, _, err = mc.ReadFrom(msg) + require.NoError(t, err) + + // Write from new connection should provide the new address on ReadFrom + _, err = cc.WriteTo([]byte("test1"), c.LocalAddr()) + require.NoError(t, err) + n, addr, err := mc.ReadFrom(msg) + require.NoError(t, err) + require.Equal(t, addr, cc.LocalAddr()) + require.Equal(t, "test1", string(msg[:n])) + + // Write from original connection should provide the original address + _, err = conns[i].WriteTo([]byte("test2"), c.LocalAddr()) + require.NoError(t, err) + n, addr, err = mc.ReadFrom(msg) + require.NoError(t, err) + require.Equal(t, addr, conns[i].LocalAddr()) + require.Equal(t, "test2", string(msg[:n])) + } +} + +func TestRemoveConnByUfrag(t *testing.T) { + c := newPacketConn(t) + m := NewUDPMux(c) + m.Start() + defer m.Close() + + // Map each ufrag to two addresses + ufrag := "a" + count := 10 + conns := make([]net.PacketConn, count) + for i := 0; i < 10; i++ { + conns[i] = newPacketConn(t) + setupMapping(t, ufrag, conns[i], m) + } + mc, err := m.GetConn(ufrag, conns[0].LocalAddr()) + require.NoError(t, err) + for i := 0; i < 10; i++ { + mc1, err := m.GetConn(ufrag, conns[i].LocalAddr()) + require.NoError(t, err) + if mc1 != mc { + t.Fatalf("expected the two muxed connections to be same") + } + } + + // Now remove the ufrag + m.RemoveConnByUfrag(ufrag) + + // All connections should now be associated with b + ufrag = "b" + for i := 0; i < 10; i++ { + setupMapping(t, ufrag, conns[i], m) + } + mc, err = m.GetConn(ufrag, conns[0].LocalAddr()) + require.NoError(t, err) + for i := 0; i < 10; i++ { + mc1, err := m.GetConn(ufrag, conns[i].LocalAddr()) + require.NoError(t, err) + if mc1 != mc { + t.Fatalf("expected the two muxed connections to be same") + } + } + + // Should be different even if the address is the same + mc1, err := m.GetConn("a", conns[0].LocalAddr()) + require.NoError(t, err) + if mc1 == mc { + t.Fatalf("expected the two connections to be different") + } +} + +func TestMuxedConnection(t *testing.T) { + c := newPacketConn(t) + m := NewUDPMux(c) + m.Start() + defer m.Close() + + msgCount := 3 + connCount := 3 + + ufrags := []string{"a", "b", "c"} + addrUfragMap := make(map[string]string) + ufragConnsMap := make(map[string][]net.PacketConn) + for _, ufrag := range ufrags { + for i := 0; i < connCount; i++ { + cc := newPacketConn(t) + addrUfragMap[cc.LocalAddr().String()] = ufrag + ufragConnsMap[ufrag] = append(ufragConnsMap[ufrag], cc) + } + } + + done := make(chan bool, len(ufrags)) + for _, ufrag := range ufrags { + go func(ufrag string) { + for _, cc := range ufragConnsMap[ufrag] { + setupMapping(t, ufrag, cc, m) + for j := 0; j < msgCount; j++ { + cc.WriteTo([]byte(ufrag), c.LocalAddr()) + } + } + done <- true + }(ufrag) + } + for i := 0; i < len(ufrags); i++ { + <-done + } + + for _, ufrag := range ufrags { + mc, err := m.GetConn(ufrag, c.LocalAddr()) // the address is irrelevant + require.NoError(t, err) + msgs := 0 + stunRequests := 0 + msg := make([]byte, 1500) + addrPacketCount := make(map[string]int) + for i := 0; i < connCount; i++ { + for j := 0; j < msgCount+1; j++ { + n, addr1, err := mc.ReadFrom(msg) + require.NoError(t, err) + require.Equal(t, addrUfragMap[addr1.String()], ufrag) + addrPacketCount[addr1.String()]++ + if stun.IsMessage(msg[:n]) { + stunRequests++ + } else { + msgs++ + } + } + } + for addr, v := range addrPacketCount { + require.Equal(t, v, msgCount+1) // msgCount msgs + 1 STUN binding request + delete(addrUfragMap, addr) + } + require.Len(t, addrPacketCount, connCount) + } + require.Empty(t, addrUfragMap) +} diff --git a/go-libp2p/p2p/transport/webrtc/udpmux/muxed_connection.go b/go-libp2p/p2p/transport/webrtc/udpmux/muxed_connection.go new file mode 100644 index 0000000..2af5d33 --- /dev/null +++ b/go-libp2p/p2p/transport/webrtc/udpmux/muxed_connection.go @@ -0,0 +1,112 @@ +package udpmux + +import ( + "context" + "errors" + "net" + "time" + + pool "github.com/libp2p/go-buffer-pool" +) + +type packet struct { + buf []byte + addr net.Addr +} + +var _ net.PacketConn = &muxedConnection{} + +const queueLen = 128 + +// muxedConnection provides a net.PacketConn abstraction +// over packetQueue and adds the ability to store addresses +// from which this connection (indexed by ufrag) received +// data. +type muxedConnection struct { + ctx context.Context + cancel context.CancelFunc + onClose func() + queue chan packet + mux *UDPMux +} + +var _ net.PacketConn = &muxedConnection{} + +func newMuxedConnection(mux *UDPMux, onClose func()) *muxedConnection { + ctx, cancel := context.WithCancel(mux.ctx) + return &muxedConnection{ + ctx: ctx, + cancel: cancel, + queue: make(chan packet, queueLen), + onClose: onClose, + mux: mux, + } +} + +func (c *muxedConnection) Push(buf []byte, addr net.Addr) error { + select { + case <-c.ctx.Done(): + return errors.New("closed") + default: + } + select { + case c.queue <- packet{buf: buf, addr: addr}: + return nil + default: + return errors.New("queue full") + } +} + +func (c *muxedConnection) ReadFrom(buf []byte) (int, net.Addr, error) { + select { + case p := <-c.queue: + n := copy(buf, p.buf) // This might discard parts of the packet, if p is too short + if n < len(p.buf) { + log.Debugf("short read, had %d, read %d", len(p.buf), n) + } + pool.Put(p.buf) + return n, p.addr, nil + case <-c.ctx.Done(): + return 0, nil, c.ctx.Err() + } +} + +func (c *muxedConnection) WriteTo(p []byte, addr net.Addr) (n int, err error) { + return c.mux.writeTo(p, addr) +} + +func (c *muxedConnection) Close() error { + select { + case <-c.ctx.Done(): + return nil + default: + } + c.onClose() + c.cancel() + // drain the packet queue + for { + select { + case p := <-c.queue: + pool.Put(p.buf) + default: + return nil + } + } +} + +func (c *muxedConnection) LocalAddr() net.Addr { return c.mux.socket.LocalAddr() } + +func (*muxedConnection) SetDeadline(t time.Time) error { + // no deadline is desired here + return nil +} + +func (*muxedConnection) SetReadDeadline(t time.Time) error { + // no read deadline is desired here + return nil +} + +func (*muxedConnection) SetWriteDeadline(t time.Time) error { + // no write deadline is desired here + return nil +} diff --git a/go-libp2p/p2p/transport/websocket/addrs_test.go b/go-libp2p/p2p/transport/websocket/addrs_test.go index e2779fd..3c5ba50 100644 --- a/go-libp2p/p2p/transport/websocket/addrs_test.go +++ b/go-libp2p/p2p/transport/websocket/addrs_test.go @@ -73,9 +73,9 @@ func TestListeningOnDNSAddr(t *testing.T) { require.NoError(t, err) addr := ln.Multiaddr() first, rest := ma.SplitFirst(addr) - require.Equal(t, first.Protocol().Code, ma.P_DNS) - require.Equal(t, first.Value(), "localhost") + require.Equal(t, ma.P_DNS, first.Protocol().Code) + require.Equal(t, "localhost", first.Value()) next, _ := ma.SplitFirst(rest) - require.Equal(t, next.Protocol().Code, ma.P_TCP) - require.NotEqual(t, next.Value(), "0") + require.Equal(t, ma.P_TCP, next.Protocol().Code) + require.NotEqual(t, 0, next.Value()) } diff --git a/go-libp2p/p2p/transport/websocket/websocket.go b/go-libp2p/p2p/transport/websocket/websocket.go index e196512..5142ca9 100644 --- a/go-libp2p/p2p/transport/websocket/websocket.go +++ b/go-libp2p/p2p/transport/websocket/websocket.go @@ -120,7 +120,7 @@ func (t *WebsocketTransport) Proxy() bool { return false } -func (t *WebsocketTransport) Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) { +func (t *WebsocketTransport) Resolve(_ context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) { parsed, err := parseWebsocketMultiaddr(maddr) if err != nil { return nil, err @@ -136,7 +136,7 @@ func (t *WebsocketTransport) Resolve(ctx context.Context, maddr ma.Multiaddr) ([ // We don't have an sni component, we'll use dns/dnsaddr ma.ForEach(parsed.restMultiaddr, func(c ma.Component) bool { switch c.Protocol().Code { - case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR: + case ma.P_DNS, ma.P_DNS4, ma.P_DNS6: // err shouldn't happen since this means we couldn't parse a dns hostname for an sni value. parsed.sni, err = ma.NewComponent("sni", c.Value()) return false diff --git a/go-libp2p/p2p/transport/websocket/websocket_test.go b/go-libp2p/p2p/transport/websocket/websocket_test.go index aa06c62..2023ee3 100644 --- a/go-libp2p/p2p/transport/websocket/websocket_test.go +++ b/go-libp2p/p2p/transport/websocket/websocket_test.go @@ -525,12 +525,13 @@ func TestWriteZero(t *testing.T) { func TestResolveMultiaddr(t *testing.T) { // map[unresolved]resolved testCases := map[string]string{ + "/dns/example.com/tcp/1234/wss": "/dns/example.com/tcp/1234/tls/sni/example.com/ws", "/dns4/example.com/tcp/1234/wss": "/dns4/example.com/tcp/1234/tls/sni/example.com/ws", "/dns6/example.com/tcp/1234/wss": "/dns6/example.com/tcp/1234/tls/sni/example.com/ws", - "/dnsaddr/example.com/tcp/1234/wss": "/dnsaddr/example.com/tcp/1234/tls/sni/example.com/ws", + "/dnsaddr/example.com/tcp/1234/wss": "/dnsaddr/example.com/tcp/1234/wss", "/dns4/example.com/tcp/1234/tls/ws": "/dns4/example.com/tcp/1234/tls/sni/example.com/ws", "/dns6/example.com/tcp/1234/tls/ws": "/dns6/example.com/tcp/1234/tls/sni/example.com/ws", - "/dnsaddr/example.com/tcp/1234/tls/ws": "/dnsaddr/example.com/tcp/1234/tls/sni/example.com/ws", + "/dnsaddr/example.com/tcp/1234/tls/ws": "/dnsaddr/example.com/tcp/1234/tls/ws", } for unresolved, expectedMA := range testCases { diff --git a/go-libp2p/p2p/transport/webtransport/cert_manager_test.go b/go-libp2p/p2p/transport/webtransport/cert_manager_test.go index 29999a8..942d471 100644 --- a/go-libp2p/p2p/transport/webtransport/cert_manager_test.go +++ b/go-libp2p/p2p/transport/webtransport/cert_manager_test.go @@ -166,7 +166,7 @@ func TestGetCurrentBucketStartTimeIsWithinBounds(t *testing.T) { offset = offset % certValidity // Bound this to 100 years - timeSinceUnixEpoch = time.Duration(timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100)) + timeSinceUnixEpoch = timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100) // Start a bit further in the future to avoid edge cases around epoch timeSinceUnixEpoch += time.Hour * 24 * 365 start := time.UnixMilli(timeSinceUnixEpoch.Milliseconds()) diff --git a/go-libp2p/p2p/transport/webtransport/listener.go b/go-libp2p/p2p/transport/webtransport/listener.go index 337239f..2a7c354 100644 --- a/go-libp2p/p2p/transport/webtransport/listener.go +++ b/go-libp2p/p2p/transport/webtransport/listener.go @@ -212,5 +212,14 @@ func (l *listener) Close() error { l.reuseListener.Close() err := l.server.Close() <-l.serverClosed +loop: + for { + select { + case conn := <-l.queue: + conn.Close() + default: + break loop + } + } return err } diff --git a/go-libp2p/p2p/transport/webtransport/mock_connection_gater_test.go b/go-libp2p/p2p/transport/webtransport/mock_connection_gater_test.go index c6e7dba..245d254 100644 --- a/go-libp2p/p2p/transport/webtransport/mock_connection_gater_test.go +++ b/go-libp2p/p2p/transport/webtransport/mock_connection_gater_test.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater) +// +// Generated by this command: +// +// mockgen -package libp2pwebtransport_test -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater +// // Package libp2pwebtransport_test is a generated GoMock package. package libp2pwebtransport_test @@ -7,11 +12,11 @@ package libp2pwebtransport_test import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" control "github.com/libp2p/go-libp2p/core/control" network "github.com/libp2p/go-libp2p/core/network" peer "github.com/libp2p/go-libp2p/core/peer" multiaddr "github.com/multiformats/go-multiaddr" + gomock "go.uber.org/mock/gomock" ) // MockConnectionGater is a mock of ConnectionGater interface. @@ -46,7 +51,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool } // InterceptAccept indicates an expected call of InterceptAccept. -func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0) } @@ -60,7 +65,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul } // InterceptAddrDial indicates an expected call of InterceptAddrDial. -func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1) } @@ -74,7 +79,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool { } // InterceptPeerDial indicates an expected call of InterceptPeerDial. -func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0) } @@ -88,7 +93,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer } // InterceptSecured indicates an expected call of InterceptSecured. -func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2) } @@ -103,7 +108,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro } // InterceptUpgraded indicates an expected call of InterceptUpgraded. -func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call { +func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0) } diff --git a/go-libp2p/p2p/transport/webtransport/multiaddr.go b/go-libp2p/p2p/transport/webtransport/multiaddr.go index d6930af..bd90638 100644 --- a/go-libp2p/p2p/transport/webtransport/multiaddr.go +++ b/go-libp2p/p2p/transport/webtransport/multiaddr.go @@ -89,17 +89,23 @@ func IsWebtransportMultiaddr(multiaddr ma.Multiaddr) (bool, int) { certhashCount := 0 ma.ForEach(multiaddr, func(c ma.Component) bool { - if c.Protocol().Code == ma.P_QUIC_V1 && state == init { - state = foundUDP - } - if c.Protocol().Code == ma.P_QUIC_V1 && state == foundUDP { - state = foundQuicV1 - } - if c.Protocol().Code == ma.P_WEBTRANSPORT && state == foundQuicV1 { - state = foundWebTransport - } - if c.Protocol().Code == ma.P_CERTHASH && state == foundWebTransport { - certhashCount++ + switch c.Protocol().Code { + case ma.P_UDP: + if state == init { + state = foundUDP + } + case ma.P_QUIC_V1: + if state == foundUDP { + state = foundQuicV1 + } + case ma.P_WEBTRANSPORT: + if state == foundQuicV1 { + state = foundWebTransport + } + case ma.P_CERTHASH: + if state == foundWebTransport { + certhashCount++ + } } return true }) diff --git a/go-libp2p/p2p/transport/webtransport/multiaddr_test.go b/go-libp2p/p2p/transport/webtransport/multiaddr_test.go index 4e9d7c3..3f0a3ec 100644 --- a/go-libp2p/p2p/transport/webtransport/multiaddr_test.go +++ b/go-libp2p/p2p/transport/webtransport/multiaddr_test.go @@ -117,6 +117,7 @@ func TestIsWebtransportMultiaddr(t *testing.T) { {addr: "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport/certhash/" + fooHash, want: true, certhashCount: 1}, {addr: "/ip4/1.2.3.4/udp/60042/quic-v1/webtransport/certhash/" + fooHash + "/certhash/" + barHash, want: true, certhashCount: 2}, {addr: "/dns4/example.com/udp/60042/quic-v1/webtransport/certhash/" + fooHash, want: true, certhashCount: 1}, + {addr: "/dns4/example.com/tcp/60042/quic-v1/webtransport/certhash/" + fooHash, want: false}, {addr: "/dns4/example.com/udp/60042/webrtc/certhash/" + fooHash, want: false}, } diff --git a/go-libp2p/p2p/transport/webtransport/transport.go b/go-libp2p/p2p/transport/webtransport/transport.go index 957d2ff..9717270 100644 --- a/go-libp2p/p2p/transport/webtransport/transport.go +++ b/go-libp2p/p2p/transport/webtransport/transport.go @@ -79,7 +79,7 @@ type transport struct { noise *noise.Transport connMx sync.Mutex - conns map[uint64]*conn // using quic-go's ConnectionTracingKey as map key + conns map[quic.ConnectionTracingID]*conn // using quic-go's ConnectionTracingKey as map key } var _ tpt.Transport = &transport{} @@ -105,7 +105,7 @@ func New(key ic.PrivKey, psk pnet.PSK, connManager *quicreuse.ConnManager, gater gater: gater, clock: clock.New(), connManager: connManager, - conns: map[uint64]*conn{}, + conns: map[quic.ConnectionTracingID]*conn{}, } for _, opt := range opts { if err := opt(t); err != nil { @@ -203,11 +203,10 @@ func (t *transport) dial(ctx context.Context, addr ma.Multiaddr, url, sni string return nil, err } dialer := webtransport.Dialer{ - RoundTripper: &http3.RoundTripper{ - Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { - return conn.(quic.EarlyConnection), nil - }, + DialAddr: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { + return conn.(quic.EarlyConnection), nil }, + QUICConfig: t.connManager.ClientConfig().Clone(), } rsp, sess, err := dialer.Dial(ctx, url, nil) if err != nil { @@ -348,7 +347,7 @@ func (t *transport) allowWindowIncrease(conn quic.Connection, size uint64) bool t.connMx.Lock() defer t.connMx.Unlock() - c, ok := t.conns[conn.Context().Value(quic.ConnectionTracingKey).(uint64)] + c, ok := t.conns[conn.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID)] if !ok { return false } @@ -357,13 +356,13 @@ func (t *transport) allowWindowIncrease(conn quic.Connection, size uint64) bool func (t *transport) addConn(sess *webtransport.Session, c *conn) { t.connMx.Lock() - t.conns[sess.Context().Value(quic.ConnectionTracingKey).(uint64)] = c + t.conns[sess.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID)] = c t.connMx.Unlock() } func (t *transport) removeConn(sess *webtransport.Session) { t.connMx.Lock() - delete(t.conns, sess.Context().Value(quic.ConnectionTracingKey).(uint64)) + delete(t.conns, sess.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID)) t.connMx.Unlock() } diff --git a/go-libp2p/p2p/transport/webtransport/transport_test.go b/go-libp2p/p2p/transport/webtransport/transport_test.go index 749d12f..f6c850a 100644 --- a/go-libp2p/p2p/transport/webtransport/transport_test.go +++ b/go-libp2p/p2p/transport/webtransport/transport_test.go @@ -28,7 +28,6 @@ import ( libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" "github.com/benbjohnson/clock" - "github.com/golang/mock/gomock" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/multiformats/go-multibase" @@ -37,6 +36,7 @@ import ( "github.com/quic-go/quic-go/http3" quicproxy "github.com/quic-go/quic-go/integrationtests/tools/proxy" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) const clockSkewAllowance = time.Hour @@ -97,7 +97,7 @@ func getCerthashComponent(t *testing.T, b []byte) ma.Multiaddr { func newConnManager(t *testing.T, opts ...quicreuse.Option) *quicreuse.ConnManager { t.Helper() - cm, err := quicreuse.NewConnManager([32]byte{}, opts...) + cm, err := quicreuse.NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}, opts...) require.NoError(t, err) t.Cleanup(func() { cm.Close() }) return cm @@ -178,7 +178,7 @@ func TestHashVerification(t *testing.T) { var trErr *quic.TransportError require.ErrorAs(t, err, &trErr) require.Equal(t, quic.TransportErrorCode(0x12a), trErr.ErrorCode) - require.Contains(t, trErr.ErrorMessage, "cert hash not found") + require.Contains(t, errors.Unwrap(trErr).Error(), "cert hash not found") }) t.Run("fails when adding a wrong hash", func(t *testing.T) { @@ -360,7 +360,7 @@ func TestResourceManagerListening(t *testing.T) { } // TODO: unify somehow. We do the same in libp2pquic. -//go:generate sh -c "go run github.com/golang/mock/mockgen -package libp2pwebtransport_test -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater && go run golang.org/x/tools/cmd/goimports -w mock_connection_gater_test.go" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package libp2pwebtransport_test -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater && go run golang.org/x/tools/cmd/goimports -w mock_connection_gater_test.go" func TestConnectionGaterDialing(t *testing.T) { ctrl := gomock.NewController(t) @@ -650,7 +650,7 @@ func serverSendsBackValidCert(t *testing.T, timeSinceUnixEpoch time.Duration, ke } // Bound this to 100 years - timeSinceUnixEpoch = time.Duration(timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100)) + timeSinceUnixEpoch = timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100) // Start a bit further in the future to avoid edge cases around epoch timeSinceUnixEpoch += time.Hour * 24 * 365 start := time.UnixMilli(timeSinceUnixEpoch.Milliseconds()) @@ -729,7 +729,7 @@ func TestServerRotatesCertCorrectly(t *testing.T) { } // Bound this to 100 years - timeSinceUnixEpoch = time.Duration(timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100)) + timeSinceUnixEpoch = timeSinceUnixEpoch % (time.Hour * 24 * 365 * 100) // Start a bit further in the future to avoid edge cases around epoch timeSinceUnixEpoch += time.Hour * 24 * 365 start := time.UnixMilli(timeSinceUnixEpoch.Milliseconds()) diff --git a/go-libp2p/package-list.json b/go-libp2p/package-list.json deleted file mode 100644 index fec3fac..0000000 --- a/go-libp2p/package-list.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "columns": [ - "Name", - "CI/Travis", - "Coverage", - "Description" - ], - "rows": [ - "Libp2p", - ["libp2p/go-libp2p", "go-libp2p", "go-libp2p entry point"], - ["libp2p/go-libp2p-core", "go-libp2p-core", "core interfaces, types, and abstractions"], - ["libp2p/go-libp2p-blankhost", "go-libp2p-blankhost", "minimal implementation of the \"host\" interface"], - - "Network", - ["libp2p/go-libp2p-swarm", "go-libp2p-swarm", "reference implementation of network state machine"], - - "Transport", - ["libp2p/go-ws-transport", "go-ws-transport", "WebSocket transport"], - ["libp2p/go-tcp-transport", "go-tcp-transport", "TCP transport"], - ["libp2p/go-libp2p-quic-transport", "go-libp2p-quic-transport", "QUIC transport"], - ["libp2p/go-udp-transport", "go-udp-transport", "UDP transport"], - ["libp2p/go-utp-transport", "go-utp-transport", "uTorrent transport (UTP)"], - ["libp2p/go-libp2p-circuit", "go-libp2p-circuit", "relay transport"], - ["libp2p/go-libp2p-transport-upgrader", "go-libp2p-transport-upgrader", "upgrades multiaddr-net connections into full libp2p transports"], - ["libp2p/go-libp2p-reuseport-transport", "go-libp2p-reuseport-transport", "partial transport for building transports that reuse ports"], - - "Encrypted Channels", - ["libp2p/go-libp2p-secio", "go-libp2p-secio", "SecIO crypto channel"], - ["libp2p/go-libp2p-tls-transport", "go-libp2p-tls-transport", "TLS 1.3+ crypto channel"], - ["libp2p/go-conn-security-multistream", "go-conn-security-multistream", "multistream multiplexed meta crypto channel"], - - "Private Network", - ["libp2p/go-libp2p-pnet", "go-libp2p-pnet", "reference private networking implementation"], - - "Stream Muxers", - ["libp2p/go-libp2p-yamux", "go-libp2p-yamux", "YAMUX stream multiplexer"], - ["libp2p/go-libp2p-mplex", "go-libp2p-mplex", "MPLEX stream multiplexer"], - - "NAT Traversal", - ["libp2p/go-libp2p-nat", "go-libp2p-nat"], - - "Peerstore", - ["libp2p/go-libp2p-peerstore", "go-libp2p-peerstore", "reference implementation of peer metadata storage component"], - - "Connection Manager", - ["libp2p/go-libp2p-connmgr", "go-libp2p-connmgr", "reference implementation of connection manager"], - - "Routing", - ["libp2p/go-libp2p-record", "go-libp2p-record", "record type and validator logic"], - ["libp2p/go-libp2p-kad-dht", "go-libp2p-kad-dht", "Kademlia-like router"], - ["libp2p/go-libp2p-kbucket", "go-libp2p-kbucket", "Kademlia routing table helper types"], - ["libp2p/go-libp2p-coral-dht", "go-libp2p-coral-dht", "Router based on Coral DHT"], - ["libp2p/go-libp2p-pubsub-router", "go-libp2p-pubsub-router", "record-store over pubsub adapter"], - - "Consensus", - ["libp2p/go-libp2p-consensus", "go-libp2p-consensus", "consensus protocols interfaces"], - ["libp2p/go-libp2p-raft", "go-libp2p-raft", "consensus implementation over raft"], - - "Pubsub", - ["libp2p/go-libp2p-pubsub", "go-libp2p-pubsub", "multiple pubsub over libp2p implementations"], - - "RPC", - ["libp2p/go-libp2p-gorpc", "go-libp2p-gorpc", "a simple RPC library for libp2p"], - - "Utilities/miscellaneous", - ["libp2p/go-libp2p-loggables", "go-libp2p-loggables", "logging helpers"], - ["libp2p/go-maddr-filter", "go-maddr-filter", "multiaddr filtering helpers"], - ["libp2p/go-libp2p-netutil", "go-libp2p-netutil", "misc utilities"], - ["libp2p/go-msgio", "go-msgio", "length prefixed data channel"], - ["libp2p/go-addr-util", "go-addr-util", "address utilities for libp2p swarm"], - ["libp2p/go-buffer-pool", "go-buffer-pool", "a variable size buffer pool for go"], - ["libp2p/go-libp2p-routing-helpers", "go-libp2p-routing-helpers", "routing helpers"], - ["libp2p/go-reuseport", "go-reuseport", "enables reuse of addresses"], - ["libp2p/go-sockaddr", "go-sockaddr", "utils for sockaddr conversions"], - ["libp2p/go-flow-metrics", "go-flow-metrics", "metrics library"], - ["libp2p/go-libp2p-gostream", "go-libp2p-gostream", "Go 'net' wrappers for libp2p"], - ["libp2p/go-libp2p-http", "go-libp2p-http", "HTTP on top of libp2p streams"], - - "Testing and examples", - ["libp2p/go-libp2p-testing", "go-libp2p-testing", "a collection of testing utilities for libp2p"] - ] -} diff --git a/go-libp2p/test-plans/PingDockerfile b/go-libp2p/test-plans/PingDockerfile index 1f19562..5c413aa 100644 --- a/go-libp2p/test-plans/PingDockerfile +++ b/go-libp2p/test-plans/PingDockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # This is run from the parent directory to copy the whole go-libp2p codebase -FROM golang:1.19-alpine AS builder +FROM golang:1.21-alpine AS builder WORKDIR /app/ @@ -14,4 +14,4 @@ FROM alpine WORKDIR /app COPY --from=builder /testplan /testplan -ENTRYPOINT [ "/testplan"] \ No newline at end of file +ENTRYPOINT [ "/testplan"] diff --git a/go-libp2p/test-plans/README.md b/go-libp2p/test-plans/README.md index 1d180aa..0606f85 100644 --- a/go-libp2p/test-plans/README.md +++ b/go-libp2p/test-plans/README.md @@ -10,10 +10,10 @@ can dial/listen for ourselves we can do the following: 1. Start redis (needed by the tests): `docker run --rm -it -p 6379:6379 redis/redis-stack`. -2. In one terminal run the dialer: `REDIS_ADDR=localhost:6379 ip="0.0.0.0" +2. In one terminal run the dialer: `redis_addr=localhost:6379 ip="0.0.0.0" transport=quic-v1 security=quic muxer=quic is_dialer="true" go run ./cmd/ping` -3. In another terminal, run the listener: `REDIS_ADDR=localhost:6379 +3. In another terminal, run the listener: `redis_addr=localhost:6379 ip="0.0.0.0" transport=quic-v1 security=quic muxer=quic is_dialer="false" go run ./cmd/ping` @@ -29,9 +29,9 @@ the following (from the root directory of this repository): 1. Build the image: `docker build -t go-libp2p-head -f test-plans/PingDockerfile .`. 2. Build the images for all released versions in `libp2p/test-plans`: `(cd /libp2p/test-plans/multidim-interop/ && make)`. + to >/libp2p/test-plans/transport-interop/ && make)`. 3. Run the test: ``` -GO_LIBP2P="$PWD"; (cd /libp2p/test-plans/multidim-interop/ && npm run test -- --extra-version=$GO_LIBP2P/test-plans/ping-version.json --name-filter="go-libp2p-head") +GO_LIBP2P="$PWD"; (cd /libp2p/test-plans/transport-interop/ && npm run test -- --extra-version=$GO_LIBP2P/test-plans/ping-version.json --name-filter="go-libp2p-head") ``` diff --git a/go-libp2p/test-plans/cmd/ping/main.go b/go-libp2p/test-plans/cmd/ping/main.go index 24a3dbc..c836a72 100644 --- a/go-libp2p/test-plans/cmd/ping/main.go +++ b/go-libp2p/test-plans/cmd/ping/main.go @@ -15,13 +15,14 @@ import ( "strconv" "time" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + "github.com/go-redis/redis/v8" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/muxer/mplex" "github.com/libp2p/go-libp2p/p2p/muxer/yamux" "github.com/libp2p/go-libp2p/p2p/protocol/ping" - noise "github.com/libp2p/go-libp2p/p2p/security/noise" + "github.com/libp2p/go-libp2p/p2p/security/noise" libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/tcp" @@ -98,15 +99,15 @@ func main() { case "tcp": options = append(options, libp2p.Transport(tcp.NewTCPTransport)) listenAddr = fmt.Sprintf("/ip4/%s/tcp/0", ip) - case "quic": - options = append(options, libp2p.Transport(libp2pquic.NewTransport)) - listenAddr = fmt.Sprintf("/ip4/%s/udp/0/quic", ip) case "quic-v1": options = append(options, libp2p.Transport(libp2pquic.NewTransport)) listenAddr = fmt.Sprintf("/ip4/%s/udp/0/quic-v1", ip) case "webtransport": options = append(options, libp2p.Transport(libp2pwebtransport.New)) listenAddr = fmt.Sprintf("/ip4/%s/udp/0/quic-v1/webtransport", ip) + case "webrtc-direct": + options = append(options, libp2p.Transport(libp2pwebrtc.New)) + listenAddr = fmt.Sprintf("/ip4/%s/udp/0/webrtc-direct", ip) default: log.Fatalf("Unsupported transport: %s", transport) } @@ -116,13 +117,11 @@ func main() { var skipMuxer bool var skipSecureChannel bool switch transport { - case "quic": - fallthrough case "quic-v1": fallthrough case "webtransport": fallthrough - case "webrtc": + case "webrtc-direct": skipMuxer = true skipSecureChannel = true } @@ -142,8 +141,6 @@ func main() { switch muxer { case "yamux": options = append(options, libp2p.Muxer("/yamux/1.0.0", yamux.DefaultTransport)) - case "mplex": - options = append(options, libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport)) default: log.Fatalf("Unsupported muxer: %s", muxer) } diff --git a/go-libp2p/test-plans/go.mod b/go-libp2p/test-plans/go.mod index c752cbe..64361ed 100644 --- a/go-libp2p/test-plans/go.mod +++ b/go-libp2p/test-plans/go.mod @@ -1,11 +1,11 @@ module github.com/libp2p/go-libp2p/test-plans/m/v2 -go 1.19 +go 1.21 require ( github.com/go-redis/redis/v8 v8.11.5 github.com/libp2p/go-libp2p v0.0.0 - github.com/multiformats/go-multiaddr v0.10.1 + github.com/multiformats/go-multiaddr v0.12.4 ) require ( @@ -14,43 +14,40 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/huin/goupnp v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect - github.com/libp2p/go-mplex v0.7.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.3.0 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // 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 @@ -62,37 +59,54 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pion/datachannel v1.5.6 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/ice/v2 v2.3.24 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.40 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.15.1 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.3 // indirect - github.com/quic-go/qtls-go1-20 v0.2.3 // indirect - github.com/quic-go/quic-go v0.36.3 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.20.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.21.1 // indirect + go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - golang.org/x/tools v0.11.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + golang.org/x/tools v0.21.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go-libp2p/test-plans/go.sum b/go-libp2p/test-plans/go.sum index f5d7baf..63eac7a 100644 --- a/go-libp2p/test-plans/go.sum +++ b/go-libp2p/test-plans/go.sum @@ -37,8 +37,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -49,16 +50,18 @@ github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0 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/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +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-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -75,39 +78,37 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA= -github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/uuid v1.3.1/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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -120,38 +121,37 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-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= -github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= -github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= -github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= @@ -159,15 +159,13 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -189,8 +187,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.10.1 h1:HghtFrWyZEPrpTvgAMFJi6gFdgHfs2cb0pyfDsk+lqU= -github.com/multiformats/go-multiaddr v0.10.1/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -202,53 +200,98 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +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/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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= -github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= -github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.36.3 h1:f+yOqeGhMoRX7/M3wmEw/djhzKWr15FtQysox85/834= -github.com/quic-go/quic-go v0.36.3/go.mod h1:qxQumdeKw5GmWs1OsTZZnOxzSI+RJWuhf1O8FN35L2o= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -281,12 +324,20 @@ github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +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.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= @@ -294,22 +345,24 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= -go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= +go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.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.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -320,11 +373,18 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= -golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -334,8 +394,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -352,8 +414,17 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +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.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -367,8 +438,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -384,19 +457,47 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -408,10 +509,11 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -432,22 +534,23 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go-libp2p/test-plans/ping-version.json b/go-libp2p/test-plans/ping-version.json index b7ad530..705934f 100644 --- a/go-libp2p/test-plans/ping-version.json +++ b/go-libp2p/test-plans/ping-version.json @@ -5,16 +5,15 @@ "tcp", "ws", "wss", - "quic", "quic-v1", - "webtransport" + "webtransport", + "webrtc-direct" ], "secureChannels": [ "tls", "noise" ], "muxers": [ - "mplex", "yamux" ] -} \ No newline at end of file +} diff --git a/go-libp2p/tools.go b/go-libp2p/tools.go index 46a8037..7a650d9 100644 --- a/go-libp2p/tools.go +++ b/go-libp2p/tools.go @@ -3,7 +3,7 @@ package libp2p import ( - _ "github.com/golang/mock/mockgen" + _ "go.uber.org/mock/mockgen" _ "golang.org/x/tools/cmd/goimports" _ "google.golang.org/protobuf/cmd/protoc-gen-go" ) diff --git a/go-libp2p/version.json b/go-libp2p/version.json index a99fc2b..fb0aea4 100644 --- a/go-libp2p/version.json +++ b/go-libp2p/version.json @@ -1,3 +1,3 @@ { - "version": "v0.29.0" + "version": "v0.35.0" } diff --git a/node/config/config.go b/node/config/config.go index 414693e..624537b 100644 --- a/node/config/config.go +++ b/node/config/config.go @@ -9,6 +9,7 @@ import ( "io/fs" "os" "path/filepath" + "strings" "github.com/cloudflare/circl/sign/ed448" "github.com/libp2p/go-libp2p/core/crypto" @@ -45,31 +46,31 @@ func NewConfig(configPath string) (*Config, error) { } var BootstrapPeers = []string{ - "/dns/bootstrap.quilibrium.com/udp/8336/quic/p2p/Qme3g6rJWuz8HVXxpDb7aV2hiFq8bZJNqxMmwzmASzfq1M", - "/dns/quaalude.quilibrium.com/udp/8336/quic/p2p/QmYruNcruYNgyTKeUqJSxjbuTFYWYDw2r5df9YKMGWCRKA", - "/dns/quecifer.quilibrium.com/udp/8336/quic/p2p/QmdWF9bGTH5mwJXkxrG859HA5r34MxXtMSTuEikSMDSESv", - "/dns/quantum.quilibrium.com/udp/8336/quic/p2p/QmbmVeKnSWK9HHAQHSS714XU3gx77TrS356JmHmKFj7q7M", - "/dns/quidditas.quilibrium.com/udp/8336/quic/p2p/QmR1rF5E9zAob9FZyMF7uTUM27D7GYtX9RaiSsNY9UP72J", - "/dns/quillon.quilibrium.com/udp/8336/quic/p2p/QmWgHv6z3tyimW4JvrvYRgsJEimgV7J2xbE7QEpFNPvAnB", - "/dns/quidditch.quilibrium.com/udp/8336/quic/p2p/QmbZEGuinaCndj4XLb6fteZmjmP3C1Tsgijmc5BGuUk8Ma", - "/dns/quagmire.quilibrium.com/udp/8336/quic/p2p/QmaQ9KAaKtqXhYSQ5ARQNnn8B8474cWGvvD6PgJ4gAtMrx", - "/ip4/204.186.74.46/udp/8316/quic/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", - "/ip4/103.219.170.9/udp/8336/quic/p2p/QmfEdMfmdhNoYuGVhhw5LBApHHG1rbVAHXwGWpW8s9bXeg", - "/ip4/185.143.102.84/udp/8336/quic/p2p/Qmce68gLLq9eMdwCcmd1ptfoC2nVoe861LF1cjdVHC2DwK", - "/ip4/65.109.17.13/udp/8336/quic/p2p/Qmc35n99eojSvW3PkbfBczJoSX92WmnnKh3Fg114ok3oo4", - "/ip4/65.108.194.84/udp/8336/quic/p2p/QmP8C7g9ZRiWzhqN2AgFu5onS6HwHzR6Vv1TCHxAhnCSnq", - "/dns/quil.dfcnodes.eu/udp/8336/quic/p2p/QmQaFmbYVrKSwoen5UQdaqyDq4QhXfSSLDVnYpYD4SF9tX", - "/ip4/87.98.167.207/udp/8336/quic/p2p/QmafiAXLu1JWktyfzDtD67i78GRBYCfQ4doTfq7pp7wfQ1", - "/ip4/216.244.76.122/udp/8336/quic/p2p/QmUSbMytVBUYiiGE266aZHrHrP17vLx5UJFd7o74HkDoaV", - "/ip4/216.244.79.194/udp/8336/quic/p2p/QmQn3bWk5aqaNSv9dwPjBg4qdeGBGNEB72tvuhgEc64Ki5", + "/dns/bootstrap.quilibrium.com/udp/8336/quic-v1/p2p/Qme3g6rJWuz8HVXxpDb7aV2hiFq8bZJNqxMmwzmASzfq1M", + "/dns/quaalude.quilibrium.com/udp/8336/quic-v1/p2p/QmYruNcruYNgyTKeUqJSxjbuTFYWYDw2r5df9YKMGWCRKA", + "/dns/quecifer.quilibrium.com/udp/8336/quic-v1/p2p/QmdWF9bGTH5mwJXkxrG859HA5r34MxXtMSTuEikSMDSESv", + "/dns/quantum.quilibrium.com/udp/8336/quic-v1/p2p/QmbmVeKnSWK9HHAQHSS714XU3gx77TrS356JmHmKFj7q7M", + "/dns/quidditas.quilibrium.com/udp/8336/quic-v1/p2p/QmR1rF5E9zAob9FZyMF7uTUM27D7GYtX9RaiSsNY9UP72J", + "/dns/quillon.quilibrium.com/udp/8336/quic-v1/p2p/QmWgHv6z3tyimW4JvrvYRgsJEimgV7J2xbE7QEpFNPvAnB", + "/dns/quidditch.quilibrium.com/udp/8336/quic-v1/p2p/QmbZEGuinaCndj4XLb6fteZmjmP3C1Tsgijmc5BGuUk8Ma", + "/dns/quagmire.quilibrium.com/udp/8336/quic-v1/p2p/QmaQ9KAaKtqXhYSQ5ARQNnn8B8474cWGvvD6PgJ4gAtMrx", + "/ip4/204.186.74.46/udp/8316/quic-v1/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", + "/ip4/103.219.170.9/udp/8336/quic-v1/p2p/QmfEdMfmdhNoYuGVhhw5LBApHHG1rbVAHXwGWpW8s9bXeg", + "/ip4/185.143.102.84/udp/8336/quic-v1/p2p/Qmce68gLLq9eMdwCcmd1ptfoC2nVoe861LF1cjdVHC2DwK", + "/ip4/65.109.17.13/udp/8336/quic-v1/p2p/Qmc35n99eojSvW3PkbfBczJoSX92WmnnKh3Fg114ok3oo4", + "/ip4/65.108.194.84/udp/8336/quic-v1/p2p/QmP8C7g9ZRiWzhqN2AgFu5onS6HwHzR6Vv1TCHxAhnCSnq", + "/dns/quil.dfcnodes.eu/udp/8336/quic-v1/p2p/QmQaFmbYVrKSwoen5UQdaqyDq4QhXfSSLDVnYpYD4SF9tX", + "/ip4/87.98.167.207/udp/8336/quic-v1/p2p/QmafiAXLu1JWktyfzDtD67i78GRBYCfQ4doTfq7pp7wfQ1", + "/ip4/216.244.76.122/udp/8336/quic-v1/p2p/QmUSbMytVBUYiiGE266aZHrHrP17vLx5UJFd7o74HkDoaV", + "/ip4/216.244.79.194/udp/8336/quic-v1/p2p/QmQn3bWk5aqaNSv9dwPjBg4qdeGBGNEB72tvuhgEc64Ki5", // purged peers (keep your node online to return to this list) - // "/ip4/204.186.74.47/udp/8317/quic/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", - // "/ip4/186.233.184.181/udp/8336/quic/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", - // "/dns/quil.zanshindojo.org/udp/8336/quic/p2p/QmXbbmtS5D12rEc4HWiHWr6e83SCE4jeThPP4VJpAQPvXq", - // "/ip4/144.76.104.93/udp/8336/quic/p2p/QmZejZ8DBGQ6foX9recW73GA6TqL6hCMX9ETWWW1Fb8xtx", - // "/ip4/207.246.81.38/udp/8336/quic/p2p/QmPBYgDy7snHon7PAn8nv1shApQBQz1iHb2sBBS8QSgQwW", - // "/dns/abyssia.fr/udp/8336/quic/p2p/QmS7C1UhN8nvzLJgFFf1uspMRrXjJqThHNN6AyEXp6oVUB", - // "/ip4/51.15.18.247/udp/8336/quic/p2p/QmYVaHXdFmHFeTa6oPixgjMVag6Ex7gLjE559ejJddwqzu", + // "/ip4/204.186.74.47/udp/8317/quic-v1/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", + // "/ip4/186.233.184.181/udp/8336/quic-v1/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", + // "/dns/quil.zanshindojo.org/udp/8336/quic-v1/p2p/QmXbbmtS5D12rEc4HWiHWr6e83SCE4jeThPP4VJpAQPvXq", + // "/ip4/144.76.104.93/udp/8336/quic-v1/p2p/QmZejZ8DBGQ6foX9recW73GA6TqL6hCMX9ETWWW1Fb8xtx", + // "/ip4/207.246.81.38/udp/8336/quic-v1/p2p/QmPBYgDy7snHon7PAn8nv1shApQBQz1iHb2sBBS8QSgQwW", + // "/dns/abyssia.fr/udp/8336/quic-v1/p2p/QmS7C1UhN8nvzLJgFFf1uspMRrXjJqThHNN6AyEXp6oVUB", + // "/ip4/51.15.18.247/udp/8336/quic-v1/p2p/QmYVaHXdFmHFeTa6oPixgjMVag6Ex7gLjE559ejJddwqzu", } func LoadConfig(configPath string, proverKey string) (*Config, error) { @@ -112,7 +113,7 @@ func LoadConfig(configPath string, proverKey string) (*Config, error) { }, }, P2P: &P2PConfig{ - ListenMultiaddr: "/ip4/0.0.0.0/udp/8336/quic", + ListenMultiaddr: "/ip4/0.0.0.0/udp/8336/quic-v1", BootstrapPeers: BootstrapPeers, PeerPrivKey: "", Network: 0, @@ -222,12 +223,24 @@ func LoadConfig(configPath string, proverKey string) (*Config, error) { config.Engine.GenesisSeed = genesisSeed } + // upgrade quic string to quic-v1 + if strings.HasSuffix(config.P2P.ListenMultiaddr, "/quic") { + config.P2P.ListenMultiaddr += "-v1" + } + // Slight trick here to get people on the latest bootstrap list – // if it's empty, always use latest, if it has the Q bootstrap node, always // use latest. if len(config.P2P.BootstrapPeers) == 0 || config.P2P.BootstrapPeers[0][:30] == "/dns/bootstrap.quilibrium.com/" { config.P2P.BootstrapPeers = BootstrapPeers + } else { + peers := make([]string, len(config.P2P.BootstrapPeers)) + for i, p := range config.P2P.BootstrapPeers { + // upgrade quic strings to quic-v1 + peers[i] = strings.Replace(p, "/quic/", "/quic-v1/", 1) + } + config.P2P.BootstrapPeers = peers } return config, nil diff --git a/node/go.mod b/node/go.mod index 9f7af8b..4908b0e 100644 --- a/node/go.mod +++ b/node/go.mod @@ -1,6 +1,8 @@ module source.quilibrium.com/quilibrium/monorepo/node -go 1.20 +go 1.21 + +toolchain go1.22.1 // A necessary hack until source.quilibrium.com is open to all replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology @@ -21,7 +23,7 @@ require ( github.com/libp2p/go-libp2p v0.31.0 github.com/libp2p/go-libp2p-gostream v0.6.0 github.com/libp2p/go-libp2p-kad-dht v0.23.0 - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v2 v2.4.0 source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub v0.0.0-00010101000000-000000000000 source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 @@ -29,8 +31,25 @@ require ( ) require ( + github.com/pion/datachannel v1.5.6 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/ice/v2 v2.3.24 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.40 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect + go.uber.org/mock v0.4.0 // indirect ) require ( @@ -49,7 +68,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 github.com/gtank/merlin v0.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -62,10 +81,8 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect - github.com/multiformats/go-multiaddr v0.11.0 + github.com/multiformats/go-multiaddr v0.12.4 github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.3 // indirect - github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect golang.org/x/term v0.21.0 google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect @@ -81,27 +98,26 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/flynn/noise v1.0.0 // indirect + github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/google/wire v0.5.0 github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.2 - github.com/huin/goupnp v1.2.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/huin/goupnp v1.3.0 // indirect github.com/iden3/go-iden3-crypto v0.0.15 github.com/ipfs/boxo v0.8.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect @@ -113,13 +129,13 @@ require ( github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect @@ -128,9 +144,8 @@ require ( github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/miekg/dns v1.1.58 // 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 @@ -142,33 +157,33 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.4.1 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect - github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.36.3 // indirect - github.com/quic-go/webtransport-go v0.5.3 // indirect + github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/dig v1.17.0 // indirect - go.uber.org/fx v1.20.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.21.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 golang.org/x/crypto v0.24.0 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 diff --git a/node/go.sum b/node/go.sum index 32098ba..10ddb19 100644 --- a/node/go.sum +++ b/node/go.sum @@ -53,11 +53,13 @@ github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEM github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895 h1:XANOgPYtvELQ/h4IrmPAohXqe2pWA8Bwhejr3VQoZsA= +github.com/cockroachdb/metamorphic v0.0.0-20231108215700-4ba948b56895/go.mod h1:aPd7gM9ov9M8v32Yy5NJrDyOcD8z642dqs+F0CeNXfA= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -84,8 +86,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= 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= @@ -99,11 +102,12 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= @@ -111,10 +115,11 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/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-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -130,13 +135,13 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -161,29 +166,31 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f h1:pDhu5sgp8yJlEF/g6osliIIpF9K4F5jvkULXa4daRDQ= -github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= +github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/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/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= @@ -197,11 +204,11 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU= -github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= -github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/ipfs/boxo v0.8.0 h1:UdjAJmHzQHo/j3g3b1bAcAXCj/GM6iTwvSlBDvPBNBs= @@ -243,10 +250,10 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -266,8 +273,8 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= -github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= +github.com/libp2p/go-libp2p-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-kad-dht v0.23.0 h1:sxE6LxLopp79eLeV695n7+c77V/Vn4AMF28AdM/XFqM= github.com/libp2p/go-libp2p-kad-dht v0.23.0/go.mod h1:oO5N308VT2msnQI6qi5M61wzPmJYg7Tr9e16m5n7uDU= github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA= @@ -275,6 +282,7 @@ github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aD github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= @@ -292,20 +300,18 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/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= @@ -339,8 +345,8 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10= -github.com/multiformats/go-multiaddr v0.11.0/go.mod h1:gWUm0QLR4thQ6+ZF6SXUw8YjtwQSPapICM+NmCkxHSM= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -353,8 +359,8 @@ github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= @@ -364,20 +370,66 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/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/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.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +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.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= -github.com/opencontainers/runtime-spec v1.1.0/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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -387,28 +439,24 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= -github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= -github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/quic-go/quic-go v0.36.3 h1:f+yOqeGhMoRX7/M3wmEw/djhzKWr15FtQysox85/834= -github.com/quic-go/quic-go v0.36.3/go.mod h1:qxQumdeKw5GmWs1OsTZZnOxzSI+RJWuhf1O8FN35L2o= -github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= -github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -456,6 +504,7 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -464,8 +513,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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -478,6 +529,7 @@ github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -487,13 +539,15 @@ go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyK go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= -go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= -go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= -go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= +go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -501,8 +555,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -517,13 +571,16 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -557,7 +614,12 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +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.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= @@ -574,8 +636,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -594,28 +654,47 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.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.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +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.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -633,7 +712,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= @@ -660,6 +738,7 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= @@ -685,10 +764,11 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index f16fe9c..4d2a2d2 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -583,18 +583,18 @@ func discoverPeers( continue } - logger.Debug("found peer", zap.String("peer_id", peer.ID.Pretty())) + logger.Debug("found peer", zap.String("peer_id", peer.ID.String())) err := h.Connect(ctx, peer) if err != nil { logger.Debug( "error while connecting to blossomsub peer", - zap.String("peer_id", peer.ID.Pretty()), + zap.String("peer_id", peer.ID.String()), zap.Error(err), ) } else { logger.Debug( "connected to peer", - zap.String("peer_id", peer.ID.Pretty()), + zap.String("peer_id", peer.ID.String()), ) } }