From 77203e1897c881daa183d8e29ba92105d8fb636e Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 12:42:52 +0100 Subject: [PATCH 01/32] routing: Add triert package with Xor Trie backed routing table --- go.mod | 67 ++++--- go.sum | 324 +++++++++++++++++++----------- key/key.go | 8 + key/key_test.go | 14 ++ routing/triert/table.go | 231 +++++++++++++++++++++ routing/triert/table_test.go | 377 +++++++++++++++++++++++++++++++++++ 6 files changed, 878 insertions(+), 143 deletions(-) create mode 100644 routing/triert/table.go create mode 100644 routing/triert/table_test.go diff --git a/go.mod b/go.mod index ca84034..7178772 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,10 @@ module github.com/plprobelab/go-kademlia go 1.20 require ( - github.com/benbjohnson/clock v1.3.0 + github.com/benbjohnson/clock v1.3.5 github.com/ipfs/go-cid v0.4.1 - github.com/libp2p/go-libp2p v0.27.6 + github.com/libp2p/go-libp2p v0.28.1 + github.com/libp2p/go-libp2p-xor v0.1.0 github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.9.0 github.com/multiformats/go-multibase v0.2.0 @@ -16,7 +17,7 @@ require ( go.opentelemetry.io/otel/exporters/jaeger v1.16.0 go.opentelemetry.io/otel/sdk v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 ) require ( @@ -39,27 +40,31 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect - github.com/huin/goupnp v1.1.0 // indirect + github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/huin/goupnp v1.2.0 // indirect + github.com/ipfs/boxo v0.10.2 // indirect + github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.16.4 // indirect + github.com/klauspost/compress v1.16.6 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect - github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // 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-nat v0.1.0 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.0 // indirect + github.com/libp2p/go-reuseport v0.3.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/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.53 // indirect + github.com/miekg/dns v1.1.55 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -70,38 +75,38 @@ require ( github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multistream v0.4.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.9.2 // indirect + github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/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.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/quic-go/quic-go v0.33.0 // indirect - github.com/quic-go/webtransport-go v0.5.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.0 // indirect + github.com/quic-go/quic-go v0.36.1 // indirect + github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.16.1 // indirect - go.uber.org/fx v1.19.2 // indirect + go.uber.org/dig v1.17.0 // indirect + go.uber.org/fx v1.20.0 // indirect + go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.9.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.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/crypto v0.10.0 // indirect + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect + golang.org/x/tools v0.10.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect - nhooyr.io/websocket v1.8.7 // indirect ) diff --git a/go.sum b/go.sum index 45df414..3ddac2d 100644 --- a/go.sum +++ b/go.sum @@ -7,15 +7,28 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.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/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -24,13 +37,19 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,6 +58,8 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -53,41 +74,28 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/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/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= @@ -95,113 +103,151 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= -github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU= -github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs/boxo v0.10.2 h1:kspw9HmMyKzLQxpKk417sF69i6iuf50AXtRjFqCYyL4= +github.com/ipfs/boxo v0.10.2/go.mod h1:1qgKq45mPRCxf4ZPoJV2lnXxyxucigILMJOrQrVivv8= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 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.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= +github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +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= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= -github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= 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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= 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.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.27.6 h1:KmGU5kskCaaerm53heqzfGOlrW2z8icZ+fnyqgrZs38= -github.com/libp2p/go-libp2p v0.27.6/go.mod h1:oMfQGTb9CHnrOuSM6yMmyK2lXz3qIhnkn2+oK3B1Y2g= +github.com/libp2p/go-libp2p v0.28.1 h1:YurK+ZAI6cKfASLJBVFkpVBdl3wGhFi6fusOt725ii8= +github.com/libp2p/go-libp2p v0.28.1/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-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio= +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-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-xor v0.1.0 h1:hhQwT4uGrBcuAkUGXADuPltalOdpf9aag9kaYNT2tLA= +github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= -github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= +github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -209,22 +255,26 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKo github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 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.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= 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= @@ -233,61 +283,72 @@ github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2 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-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +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.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= 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.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5/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.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/ginkgo 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/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +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/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.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= +github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= 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.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk= -github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= +github.com/quic-go/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= +github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.36.1 h1:WsG73nVtnDy1TiACxFxhQ3TqaW+DipmqzLEtNlAwZyY= +github.com/quic-go/quic-go v0.36.1/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= +github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= +github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +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= @@ -314,12 +375,23 @@ 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= 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.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -328,18 +400,23 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/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/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 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= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/exporters/jaeger v1.16.0 h1:YhxxmXZ011C0aDZKoNw+juVWAmEfv/0W2XBOv9aHTaA= @@ -350,55 +427,66 @@ go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiM go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.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.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8= -go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk= -go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY= -go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ= +go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= +go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= +go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= +go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.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= 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= +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-20190211182817-74369b46fc67/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.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 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-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/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= @@ -408,8 +496,8 @@ 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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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= @@ -423,19 +511,22 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-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-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -446,33 +537,37 @@ 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/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= 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= @@ -489,23 +584,29 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA 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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 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/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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -514,9 +615,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.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= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= 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/key/key.go b/key/key.go index b4c3fd5..253b0d1 100644 --- a/key/key.go +++ b/key/key.go @@ -75,3 +75,11 @@ func (a KadKey) Compare(b KadKey) int { func (a KadKey) Equal(b KadKey) bool { return a.Compare(b) == 0 } + +func (k KadKey) BitAt(offset int) int { + if k[offset/8]&(byte(1)<<(7-offset%8)) == 0 { + return 0 + } else { + return 1 + } +} diff --git a/key/key_test.go b/key/key_test.go index ab927f0..e5c6832 100644 --- a/key/key_test.go +++ b/key/key_test.go @@ -111,3 +111,17 @@ func TestCompare(t *testing.T) { require.Equal(t, 0, key.Compare([]byte{0x80, 0x00, 0x00, 0x00})) // a == b -> 0 require.Equal(t, -1, key.Compare([]byte{0x80, 0x00, 0x00, 0x00, 0x00})) // a is prefix of b -> -1 } + +func TestBitAt(t *testing.T) { + kk := KadKey([]byte{0b10010011, 0b11110100}) + require.Equal(t, 1, kk.BitAt(0)) + require.Equal(t, 0, kk.BitAt(1)) + require.Equal(t, 0, kk.BitAt(2)) + require.Equal(t, 1, kk.BitAt(3)) + require.Equal(t, 0, kk.BitAt(4)) + require.Equal(t, 0, kk.BitAt(5)) + require.Equal(t, 1, kk.BitAt(6)) + require.Equal(t, 1, kk.BitAt(7)) + require.Equal(t, 1, kk.BitAt(8)) + require.Equal(t, 0, kk.BitAt(15)) +} diff --git a/routing/triert/table.go b/routing/triert/table.go new file mode 100644 index 0000000..f92db02 --- /dev/null +++ b/routing/triert/table.go @@ -0,0 +1,231 @@ +package triert + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + + // "github.com/libp2p/go-libp2p-xor/kademlia" + tkey "github.com/libp2p/go-libp2p-xor/key" + "github.com/libp2p/go-libp2p-xor/trie" + "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/network/address" +) + +var _ = fmt.Println + +// TODO: move to key package and replace ErrInvalidKey +// ErrKeyWrongLength indicates a key has the wrong length +var ErrKeyWrongLength = errors.New("key has wrong length") + +// TrieRT is a routing table backed by a Xor Trie which offers good scalablity and performance +// for large networks +type TrieRT struct { + self key.KadKey + + // keymu is held during keys trie and keyNodes map mutations to serialize changes + keymu sync.Mutex + + // keys holds a pointer to an immutable trie + // any store to keys must be performed while holding keymu, loads may be performed without the lock + keys atomic.Value + + // keyNodes holds a mapping of kademlia key to node id (map[string]address.NodeID) + // note: this could be eliminated if the trie was modified to allow a tuple to be stored at each node + // any store to keyNodes must be performed while holding keymu, loads may be performed without the lock + keyNodes atomic.Value +} + +func New(self key.KadKey, bucketSize int) *TrieRT { + rt := &TrieRT{ + self: self, + } + rt.keys.Store(&trie.Trie{}) + rt.keyNodes.Store(map[string]address.NodeID{}) + return rt +} + +func (rt *TrieRT) Self() key.KadKey { + return rt.self +} + +// AddPeer tries to add a peer to the routing table +func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error) { + kk := node.Key() + if kk.Size() != rt.self.Size() { + return false, ErrKeyWrongLength + } + + rt.keymu.Lock() + defer rt.keymu.Unlock() + // load the old trie, derive a mutated variant and store it in place of the original + keys := rt.keys.Load().(*trie.Trie) + keysNext := trie.Add(keys, tkey.Key(kk)) + + // if trie is unchanged then we didn't add the key + if keysNext == keys { + return false, nil + } + + // make a copy of keyNodes + // could avoid this if we held key/nodeid tuple in the trie + keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) + keyNodesNext := make(map[string]address.NodeID, len(keyNodes)+1) + for k, v := range keyNodes { + keyNodesNext[k] = v + } + keyNodesNext[kk.Hex()] = node + + rt.keyNodes.Store(keyNodesNext) + rt.keys.Store(keysNext) + return true, nil +} + +// RemoveKey tries to remove a peer identified by its Kademlia key from the +// routing table +func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { + if kk.Size() != rt.self.Size() { + return false, ErrKeyWrongLength + } + rt.keymu.Lock() + defer rt.keymu.Unlock() + // load the old trie, derive a mutated variant and store it in place of the original + keys := rt.keys.Load().(*trie.Trie) + keysNext := trie.Remove(keys, tkey.Key(kk)) + + // if trie is unchanged then we didn't remove the key + if keysNext == keys { + return false, nil + } + + // make a copy of keyNodes without removed key + // could avoid this if we held key/nodeid tuple in the trie + keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) + if _, exists := keyNodes[kk.Hex()]; exists { + keyNodesNext := make(map[string]address.NodeID, len(keyNodes)) + for k, v := range keyNodes { + if k == kk.Hex() { + continue + } + keyNodesNext[k] = v + } + rt.keyNodes.Store(keyNodesNext) + } + + rt.keys.Store(keysNext) + return true, nil +} + +// NearestPeers returns the n closest peers to a given key +func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]address.NodeID, error) { + if kk.Size() != rt.self.Size() { + return nil, ErrKeyWrongLength + } + + keys := rt.keys.Load().(*trie.Trie) + closestKeys, err := closestAtDepth(ctx, tkey.Key(kk), keys, 0, n, make([]tkey.Key, 0, n)) + if err != nil { + return nil, err + } + keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) + + nodes := make([]address.NodeID, 0, len(closestKeys)) + for _, c := range closestKeys { + if id, ok := keyNodes[string(key.KadKey(c).Hex())]; ok { + nodes = append(nodes, id) + } + } + + return nodes, nil +} + +func closestAtDepth(ctx context.Context, k tkey.Key, t *trie.Trie, depth int, n int, found []tkey.Key) ([]tkey.Key, error) { + if ctx.Err() != nil { + return found, ctx.Err() + } + + // If we've already found enough peers, abort. + if n == len(found) { + return found, nil + } + + // Find the closest direction. + dir := k.BitAt(depth) + var chosenDir byte + if t.Branch[dir] != nil { + // There are peers in the "closer" direction. + chosenDir = dir + } else if t.Branch[1-dir] != nil { + // There are peers in the "less closer" direction. + chosenDir = 1 - dir + } else if t.Key != nil { + // We've found a leaf + return append(found, t.Key), nil + } else { + // We've found an empty node? + return found, nil + } + + var err error + // Add peers from the closest direction first, then from the other direction. + found, err = closestAtDepth(ctx, k, t.Branch[chosenDir], depth+1, n, found) + if err != nil { + return found, err + } + + return closestAtDepth(ctx, k, t.Branch[1-chosenDir], depth+1, n, found) +} + +func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { + if kk.Size() != rt.self.Size() { + return nil, ErrKeyWrongLength + } + + keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) + + if id, ok := keyNodes[string(key.KadKey(kk).Hex())]; ok { + return id, nil + } + + return nil, nil +} + +// Size returns the number of peers contained in the table. +func (rt *TrieRT) Size() int { + keys := rt.keys.Load().(*trie.Trie) + return keys.Size() +} + +// CplSize returns the number of peers in the table that share the specified common prefix length with the table's key. +func (rt *TrieRT) CplSize(cpl int) int { + keys := rt.keys.Load().(*trie.Trie) + n, err := countCpl(keys, rt.self, cpl, 0) + if err != nil { + return 0 + } + return n +} + +func countCpl(t *trie.Trie, kk key.KadKey, cpl int, depth int) (int, error) { + if t.IsLeaf() { + if t.IsEmpty() { + return 0, nil + } + keyCpl, err := kk.CommonPrefixLength(key.KadKey(t.Key)) + if err != nil { + return 0, err + } + if keyCpl == cpl { + return 1, nil + } + return 0, nil + } + + if depth == cpl { + return t.Size(), nil + } + + return countCpl(t.Branch[kk.BitAt(depth)], kk, cpl, depth+1) +} diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go new file mode 100644 index 0000000..a4486e1 --- /dev/null +++ b/routing/triert/table_test.go @@ -0,0 +1,377 @@ +package triert + +import ( + "context" + "crypto/rand" + "encoding/binary" + "strconv" + "testing" + + "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/network/address" + "github.com/stretchr/testify/require" +) + +var ( + key0 = key.KadKey(make([]byte, 32)) // 000000...000 + + key1 = keyWithPrefix("010000", 32) + key2 = keyWithPrefix("100000", 32) + key3 = keyWithPrefix("110000", 32) + key4 = keyWithPrefix("111000", 32) + key5 = keyWithPrefix("011000", 32) + key6 = keyWithPrefix("011100", 32) + key7 = keyWithPrefix("000110", 32) + key8 = keyWithPrefix("000101", 32) + key9 = keyWithPrefix("000100", 32) + key10 = keyWithPrefix("001000", 32) + key11 = keyWithPrefix("001100", 32) + + node1 = NewNode("QmPeer1", key1) + node2 = NewNode("QmPeer2", key2) + node3 = NewNode("QmPeer3", key3) + node4 = NewNode("QmPeer4", key4) + node5 = NewNode("QmPeer5", key5) + node6 = NewNode("QmPeer6", key6) + node7 = NewNode("QmPeer7", key7) + node8 = NewNode("QmPeer8", key8) + node9 = NewNode("QmPeer9", key9) + node10 = NewNode("QmPeer10", key10) + node11 = NewNode("QmPeer11", key11) +) + +func TestAddPeer(t *testing.T) { + t.Run("one", func(t *testing.T) { + rt := New(key0, 2) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) + require.Equal(t, 1, rt.Size()) + }) + + t.Run("ignore duplicate", func(t *testing.T) { + rt := New(key0, 2) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) + require.Equal(t, 1, rt.Size()) + + success, err = rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.False(t, success) + require.Equal(t, 1, rt.Size()) + }) + + t.Run("many", func(t *testing.T) { + rt := New(key0, 2) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node2) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node3) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node4) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node5) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node6) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node7) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(context.Background(), node8) + require.NoError(t, err) + require.True(t, success) + + require.Equal(t, 8, rt.Size()) + }) +} + +func TestRemovePeer(t *testing.T) { + rt := New(key0, 2) + rt.AddPeer(context.Background(), node1) + + t.Run("unknown peer", func(t *testing.T) { + success, err := rt.RemoveKey(context.Background(), key2) + require.NoError(t, err) + require.False(t, success) + }) + + t.Run("known peer", func(t *testing.T) { + success, err := rt.RemoveKey(context.Background(), key1) + require.NoError(t, err) + require.True(t, success) + }) +} + +func TestFindPeer(t *testing.T) { + t.Run("known peer", func(t *testing.T) { + rt := New(key0, 2) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) + + want := node1 + got, err := rt.Find(context.Background(), key1) + require.NoError(t, err) + require.Equal(t, want, got) + }) + + t.Run("unknown peer", func(t *testing.T) { + rt := New(key0, 2) + got, err := rt.Find(context.Background(), key2) + require.NoError(t, err) + require.Nil(t, got) + }) + + t.Run("removed peer", func(t *testing.T) { + rt := New(key0, 2) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) + + want := node1 + got, err := rt.Find(context.Background(), key1) + require.NoError(t, err) + require.Equal(t, want, got) + + success, err = rt.RemoveKey(context.Background(), key1) + require.NoError(t, err) + require.True(t, success) + + got, err = rt.Find(context.Background(), key1) + require.NoError(t, err) + require.Nil(t, got) + }) +} + +func TestNearestPeers(t *testing.T) { + ctx := context.Background() + + bucketSize := 5 + + rt := New(key0, bucketSize) + rt.AddPeer(ctx, node1) + rt.AddPeer(ctx, node2) + rt.AddPeer(ctx, node3) + rt.AddPeer(ctx, node4) + rt.AddPeer(ctx, node5) + rt.AddPeer(ctx, node6) + rt.AddPeer(ctx, node7) + rt.AddPeer(ctx, node8) + rt.AddPeer(ctx, node9) + rt.AddPeer(ctx, node10) + rt.AddPeer(ctx, node11) + + // find the 5 nearest peers to key0 + peers, err := rt.NearestPeers(ctx, key0, bucketSize) + require.NoError(t, err) + require.Equal(t, bucketSize, len(peers)) + + expectedOrder := []address.NodeID{node9, node8, node7, node10, node11} + require.Equal(t, expectedOrder, peers) + + peers, err = rt.NearestPeers(ctx, node11.Key(), 2) + require.NoError(t, err) + require.Equal(t, 2, len(peers)) +} + +func TestInvalidKeys(t *testing.T) { + ctx := context.Background() + incompatKey := key.KadKey(make([]byte, 4)) // key is shorter (4 bytes only) + incompatNode := NewNode("inv", incompatKey) + + rt := New(key0, 2) + + t.Run("add peer", func(t *testing.T) { + success, err := rt.AddPeer(ctx, incompatNode) + require.ErrorIs(t, err, ErrKeyWrongLength) + require.False(t, success) + }) + + t.Run("remove key", func(t *testing.T) { + success, err := rt.RemoveKey(ctx, incompatKey) + require.ErrorIs(t, err, ErrKeyWrongLength) + require.False(t, success) + }) + + t.Run("find", func(t *testing.T) { + nodeID, err := rt.Find(ctx, incompatKey) + require.ErrorIs(t, err, ErrKeyWrongLength) + require.Nil(t, nodeID) + }) + + t.Run("nearest peers", func(t *testing.T) { + nodeIDs, err := rt.NearestPeers(ctx, incompatKey, 2) + require.ErrorIs(t, err, ErrKeyWrongLength) + require.Nil(t, nodeIDs) + }) +} + +func TestCplSize(t *testing.T) { + t.Run("empty", func(t *testing.T) { + rt := New(key0, 2) + require.Equal(t, 0, rt.Size()) + require.Equal(t, 0, rt.CplSize(1)) + require.Equal(t, 0, rt.CplSize(2)) + require.Equal(t, 0, rt.CplSize(3)) + require.Equal(t, 0, rt.CplSize(4)) + }) + + t.Run("cpl 1", func(t *testing.T) { + ctx := context.Background() + rt := New(key0, 2) + + success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyWithPrefix("01", 32))) + require.NoError(t, err) + require.True(t, success) + require.Equal(t, 2, rt.Size()) + require.Equal(t, 2, rt.CplSize(1)) + + require.Equal(t, 0, rt.CplSize(2)) + require.Equal(t, 0, rt.CplSize(3)) + }) + + t.Run("cpl 2", func(t *testing.T) { + ctx := context.Background() + rt := New(key0, 2) + + success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyWithPrefix("001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyWithPrefix("001", 32))) + require.NoError(t, err) + require.True(t, success) + + require.Equal(t, 2, rt.Size()) + require.Equal(t, 2, rt.CplSize(2)) + + require.Equal(t, 2, rt.CplSize(1)) + require.Equal(t, 0, rt.CplSize(3)) + }) + + t.Run("cpl 3", func(t *testing.T) { + ctx := context.Background() + rt := New(key0, 2) + + success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + + require.Equal(t, 4, rt.Size()) + require.Equal(t, 4, rt.CplSize(3)) + + require.Equal(t, 4, rt.CplSize(1)) + require.Equal(t, 4, rt.CplSize(2)) + }) + + t.Run("cpl mixed", func(t *testing.T) { + ctx := context.Background() + rt := New(key0, 2) + + success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyWithPrefix("01", 32))) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(ctx, NewNode("cpl2a", keyWithPrefix("001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyWithPrefix("001", 32))) + require.NoError(t, err) + require.True(t, success) + + success, err = rt.AddPeer(ctx, NewNode("cpl3a", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyWithPrefix("0001", 32))) + require.NoError(t, err) + require.True(t, success) + + require.Equal(t, 8, rt.Size()) + require.Equal(t, 8, rt.CplSize(1)) + require.Equal(t, 6, rt.CplSize(2)) + require.Equal(t, 4, rt.CplSize(3)) + }) +} + +func keyWithPrefix(s string, length int) key.KadKey { + bits := len(s) + if bits > 64 { + panic("keyWithPrefix: prefix too long") + } + n, err := strconv.ParseInt(s, 2, 64) + if err != nil { + panic("keyWithPrefix: " + err.Error()) + } + prefix := uint64(n) << (64 - bits) + + buf := make([]byte, length) + if _, err := rand.Read(buf); err != nil { + panic("keyWithPrefix: failed to read enough entropy for key") + } + + lead := binary.BigEndian.Uint64(buf) + lead <<= bits + lead >>= bits + lead |= prefix + binary.BigEndian.PutUint64(buf, lead) + return key.KadKey(buf) +} + +type node struct { + id string + key key.KadKey +} + +func NewNode(id string, k key.KadKey) *node { + return &node{ + id: id, + key: k, + } +} + +func (n node) String() string { + return n.id +} + +func (n node) Key() key.KadKey { + return n.key +} + +func (n node) NodeID() address.NodeID { + return &n +} From 748074335b18840389a75053ad6aae9b0d8f5ca6 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:37:03 +0100 Subject: [PATCH 02/32] go mod tidy --- go.mod | 10 ++++++++-- go.sum | 21 +++++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 7178772..2b21cc3 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/libp2p/go-libp2p v0.28.1 github.com/libp2p/go-libp2p-xor v0.1.0 github.com/libp2p/go-msgio v0.3.0 - github.com/multiformats/go-multiaddr v0.9.0 + github.com/multiformats/go-multiaddr v0.10.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 @@ -48,7 +48,7 @@ require ( 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.6 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/text v0.2.0 // indirect @@ -110,3 +110,9 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) + +replace ( + github.com/quic-go/qtls-go1-19 => github.com/quic-go/qtls-go1-19 v0.2.1 + github.com/quic-go/qtls-go1-20 => github.com/quic-go/qtls-go1-20 v0.1.1 + github.com/quic-go/quic-go => github.com/quic-go/quic-go v0.33.0 +) diff --git a/go.sum b/go.sum index 3ddac2d..1fadcf1 100644 --- a/go.sum +++ b/go.sum @@ -176,8 +176,8 @@ 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.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= -github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.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= @@ -277,8 +277,8 @@ github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= -github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multiaddr v0.10.0 h1:onErs0qLf3P2oRqrYk1fAMcfrWaJb58pYY43SkEF78w= +github.com/multiformats/go-multiaddr v0.10.0/go.mod h1:jLEZsA61rwWNZQTHHnqq2HNa+4os/Hz54eqiRnsRqYQ= github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -337,12 +337,12 @@ github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuR github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= 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.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= -github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.36.1 h1:WsG73nVtnDy1TiACxFxhQ3TqaW+DipmqzLEtNlAwZyY= -github.com/quic-go/quic-go v0.36.1/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= +github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= +github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= +github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= +github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -437,6 +437,7 @@ go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= From c3ea4a4b2e8204d7efd6cc33006e347736500892 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:37:34 +0100 Subject: [PATCH 03/32] Remove unused package --- routing/triert/table.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index f92db02..2c3fcad 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -3,7 +3,6 @@ package triert import ( "context" "errors" - "fmt" "sync" "sync/atomic" @@ -14,8 +13,6 @@ import ( "github.com/plprobelab/go-kademlia/network/address" ) -var _ = fmt.Println - // TODO: move to key package and replace ErrInvalidKey // ErrKeyWrongLength indicates a key has the wrong length var ErrKeyWrongLength = errors.New("key has wrong length") From b1c73aa2797075d3611182a527d48b7a66a03569 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:38:51 +0100 Subject: [PATCH 04/32] Fix comment --- routing/triert/table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index 2c3fcad..22942ac 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -22,7 +22,7 @@ var ErrKeyWrongLength = errors.New("key has wrong length") type TrieRT struct { self key.KadKey - // keymu is held during keys trie and keyNodes map mutations to serialize changes + // keymu is held during keys and keyNodes mutations to serialize changes keymu sync.Mutex // keys holds a pointer to an immutable trie From f8be3dc2743253ea3dae51a5965db9cbdf05faad Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:40:19 +0100 Subject: [PATCH 05/32] Remove unused bucket size arg from New --- routing/triert/table.go | 2 +- routing/triert/table_test.go | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index 22942ac..a9d527a 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -35,7 +35,7 @@ type TrieRT struct { keyNodes atomic.Value } -func New(self key.KadKey, bucketSize int) *TrieRT { +func New(self key.KadKey) *TrieRT { rt := &TrieRT{ self: self, } diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index a4486e1..011e893 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -42,7 +42,7 @@ var ( func TestAddPeer(t *testing.T) { t.Run("one", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -50,7 +50,7 @@ func TestAddPeer(t *testing.T) { }) t.Run("ignore duplicate", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -63,7 +63,7 @@ func TestAddPeer(t *testing.T) { }) t.Run("many", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -101,7 +101,7 @@ func TestAddPeer(t *testing.T) { } func TestRemovePeer(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) rt.AddPeer(context.Background(), node1) t.Run("unknown peer", func(t *testing.T) { @@ -119,7 +119,7 @@ func TestRemovePeer(t *testing.T) { func TestFindPeer(t *testing.T) { t.Run("known peer", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -131,14 +131,14 @@ func TestFindPeer(t *testing.T) { }) t.Run("unknown peer", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) got, err := rt.Find(context.Background(), key2) require.NoError(t, err) require.Nil(t, got) }) t.Run("removed peer", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -161,9 +161,7 @@ func TestFindPeer(t *testing.T) { func TestNearestPeers(t *testing.T) { ctx := context.Background() - bucketSize := 5 - - rt := New(key0, bucketSize) + rt := New(key0) rt.AddPeer(ctx, node1) rt.AddPeer(ctx, node2) rt.AddPeer(ctx, node3) @@ -177,9 +175,9 @@ func TestNearestPeers(t *testing.T) { rt.AddPeer(ctx, node11) // find the 5 nearest peers to key0 - peers, err := rt.NearestPeers(ctx, key0, bucketSize) + peers, err := rt.NearestPeers(ctx, key0, 5) require.NoError(t, err) - require.Equal(t, bucketSize, len(peers)) + require.Equal(t, 5, len(peers)) expectedOrder := []address.NodeID{node9, node8, node7, node10, node11} require.Equal(t, expectedOrder, peers) @@ -194,7 +192,7 @@ func TestInvalidKeys(t *testing.T) { incompatKey := key.KadKey(make([]byte, 4)) // key is shorter (4 bytes only) incompatNode := NewNode("inv", incompatKey) - rt := New(key0, 2) + rt := New(key0) t.Run("add peer", func(t *testing.T) { success, err := rt.AddPeer(ctx, incompatNode) @@ -223,7 +221,7 @@ func TestInvalidKeys(t *testing.T) { func TestCplSize(t *testing.T) { t.Run("empty", func(t *testing.T) { - rt := New(key0, 2) + rt := New(key0) require.Equal(t, 0, rt.Size()) require.Equal(t, 0, rt.CplSize(1)) require.Equal(t, 0, rt.CplSize(2)) @@ -233,7 +231,7 @@ func TestCplSize(t *testing.T) { t.Run("cpl 1", func(t *testing.T) { ctx := context.Background() - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) require.NoError(t, err) @@ -250,7 +248,7 @@ func TestCplSize(t *testing.T) { t.Run("cpl 2", func(t *testing.T) { ctx := context.Background() - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyWithPrefix("001", 32))) require.NoError(t, err) @@ -268,7 +266,7 @@ func TestCplSize(t *testing.T) { t.Run("cpl 3", func(t *testing.T) { ctx := context.Background() - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyWithPrefix("0001", 32))) require.NoError(t, err) @@ -292,7 +290,7 @@ func TestCplSize(t *testing.T) { t.Run("cpl mixed", func(t *testing.T) { ctx := context.Background() - rt := New(key0, 2) + rt := New(key0) success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) require.NoError(t, err) From e3df916ddc728487645977cd4fb832e2af124b5f Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:44:15 +0100 Subject: [PATCH 06/32] Update comment --- routing/triert/table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index a9d527a..b7a4da8 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -18,7 +18,7 @@ import ( var ErrKeyWrongLength = errors.New("key has wrong length") // TrieRT is a routing table backed by a Xor Trie which offers good scalablity and performance -// for large networks +// for large networks. All exported methods are safe for concurrent use. type TrieRT struct { self key.KadKey From 9edf48616ef42dc9e7ae279f9ebc77b3f43d12a9 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:55:06 +0100 Subject: [PATCH 07/32] Remove use of Hex in keyNodes map --- routing/triert/table.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index b7a4da8..0935b88 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -73,7 +73,7 @@ func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error for k, v := range keyNodes { keyNodesNext[k] = v } - keyNodesNext[kk.Hex()] = node + keyNodesNext[string(kk)] = node rt.keyNodes.Store(keyNodesNext) rt.keys.Store(keysNext) @@ -100,10 +100,10 @@ func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { // make a copy of keyNodes without removed key // could avoid this if we held key/nodeid tuple in the trie keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) - if _, exists := keyNodes[kk.Hex()]; exists { + if _, exists := keyNodes[string(kk)]; exists { keyNodesNext := make(map[string]address.NodeID, len(keyNodes)) for k, v := range keyNodes { - if k == kk.Hex() { + if k == string(kk) { continue } keyNodesNext[k] = v @@ -130,7 +130,7 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add nodes := make([]address.NodeID, 0, len(closestKeys)) for _, c := range closestKeys { - if id, ok := keyNodes[string(key.KadKey(c).Hex())]; ok { + if id, ok := keyNodes[string(key.KadKey(c))]; ok { nodes = append(nodes, id) } } @@ -182,7 +182,7 @@ func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, erro keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) - if id, ok := keyNodes[string(key.KadKey(kk).Hex())]; ok { + if id, ok := keyNodes[string(key.KadKey(kk))]; ok { return id, nil } From c323ac3a96148be49493128c928c82fed26df8f5 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:36:24 +0100 Subject: [PATCH 08/32] Remove unused import Co-authored-by: Guillaume Michel - guissou --- routing/triert/table.go | 1 - 1 file changed, 1 deletion(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index 0935b88..febb42e 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -6,7 +6,6 @@ import ( "sync" "sync/atomic" - // "github.com/libp2p/go-libp2p-xor/kademlia" tkey "github.com/libp2p/go-libp2p-xor/key" "github.com/libp2p/go-libp2p-xor/trie" "github.com/plprobelab/go-kademlia/key" From e01bef18f7cdf95849cb5d510d8324f312edce34 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 09:28:03 +0100 Subject: [PATCH 09/32] Remove context from closestAtDepth --- routing/triert/table.go | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index febb42e..e161ac8 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -121,10 +121,11 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add } keys := rt.keys.Load().(*trie.Trie) - closestKeys, err := closestAtDepth(ctx, tkey.Key(kk), keys, 0, n, make([]tkey.Key, 0, n)) - if err != nil { - return nil, err + closestKeys := closestAtDepth(tkey.Key(kk), keys, 0, n, make([]tkey.Key, 0, n)) + if len(closestKeys) == 0 { + return []address.NodeID{}, nil } + keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) nodes := make([]address.NodeID, 0, len(closestKeys)) @@ -137,14 +138,10 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add return nodes, nil } -func closestAtDepth(ctx context.Context, k tkey.Key, t *trie.Trie, depth int, n int, found []tkey.Key) ([]tkey.Key, error) { - if ctx.Err() != nil { - return found, ctx.Err() - } - +func closestAtDepth(k tkey.Key, t *trie.Trie, depth int, n int, found []tkey.Key) []tkey.Key { // If we've already found enough peers, abort. if n == len(found) { - return found, nil + return found } // Find the closest direction. @@ -158,20 +155,15 @@ func closestAtDepth(ctx context.Context, k tkey.Key, t *trie.Trie, depth int, n chosenDir = 1 - dir } else if t.Key != nil { // We've found a leaf - return append(found, t.Key), nil + return append(found, t.Key) } else { // We've found an empty node? - return found, nil + return found } - var err error // Add peers from the closest direction first, then from the other direction. - found, err = closestAtDepth(ctx, k, t.Branch[chosenDir], depth+1, n, found) - if err != nil { - return found, err - } - - return closestAtDepth(ctx, k, t.Branch[1-chosenDir], depth+1, n, found) + found = closestAtDepth(k, t.Branch[chosenDir], depth+1, n, found) + return closestAtDepth(k, t.Branch[1-chosenDir], depth+1, n, found) } func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { From f3338f8d7b2b090fffa83896180ce2b017dd6c2b Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 10:01:27 +0100 Subject: [PATCH 10/32] Simplify NearestPeers --- routing/triert/table.go | 34 +++++++++++++--------------------- routing/triert/table_test.go | 2 ++ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index e161ac8..018ca5f 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -121,7 +121,7 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add } keys := rt.keys.Load().(*trie.Trie) - closestKeys := closestAtDepth(tkey.Key(kk), keys, 0, n, make([]tkey.Key, 0, n)) + closestKeys := closestAtDepth(tkey.Key(kk), keys, 0, n) if len(closestKeys) == 0 { return []address.NodeID{}, nil } @@ -138,32 +138,24 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add return nodes, nil } -func closestAtDepth(k tkey.Key, t *trie.Trie, depth int, n int, found []tkey.Key) []tkey.Key { - // If we've already found enough peers, abort. - if n == len(found) { - return found +func closestAtDepth(k tkey.Key, t *trie.Trie, depth int, n int) []tkey.Key { + if t.Key != nil { + // We've found a leaf + return []tkey.Key{t.Key} + } else if t.Branch[0] == nil && t.Branch[1] == nil { + // We've found an empty node? + return nil } // Find the closest direction. dir := k.BitAt(depth) - var chosenDir byte - if t.Branch[dir] != nil { - // There are peers in the "closer" direction. - chosenDir = dir - } else if t.Branch[1-dir] != nil { - // There are peers in the "less closer" direction. - chosenDir = 1 - dir - } else if t.Key != nil { - // We've found a leaf - return append(found, t.Key) - } else { - // We've found an empty node? + // Add peers from the closest direction first + found := closestAtDepth(k, t.Branch[dir], depth+1, n) + if len(found) == n { return found } - - // Add peers from the closest direction first, then from the other direction. - found = closestAtDepth(k, t.Branch[chosenDir], depth+1, n, found) - return closestAtDepth(k, t.Branch[1-chosenDir], depth+1, n, found) + // Didn't find enough peers in the closest direction, try the other direction. + return append(found, closestAtDepth(k, t.Branch[1-dir], depth+1, n-len(found))...) } func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 011e893..126b16c 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -350,6 +350,8 @@ func keyWithPrefix(s string, length int) key.KadKey { return key.KadKey(buf) } +var _ address.NodeID = (*node)(nil) + type node struct { id string key key.KadKey From afc7f658bf57fbd9aabbcb12cd1b7067adbdca95 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 10:34:41 +0100 Subject: [PATCH 11/32] Fix CplSize --- routing/triert/table.go | 6 ++++-- routing/triert/table_test.go | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/routing/triert/table.go b/routing/triert/table.go index 018ca5f..8e90e10 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -178,7 +178,7 @@ func (rt *TrieRT) Size() int { return keys.Size() } -// CplSize returns the number of peers in the table that share the specified common prefix length with the table's key. +// CplSize returns the number of peers in the table whose longest common prefix with the table's key is of length cpl. func (rt *TrieRT) CplSize(cpl int) int { keys := rt.keys.Load().(*trie.Trie) n, err := countCpl(keys, rt.self, cpl, 0) @@ -189,6 +189,7 @@ func (rt *TrieRT) CplSize(cpl int) int { } func countCpl(t *trie.Trie, kk key.KadKey, cpl int, depth int) (int, error) { + // special cases for very small tables where keys may be placed higher in the trie due to low population if t.IsLeaf() { if t.IsEmpty() { return 0, nil @@ -204,7 +205,8 @@ func countCpl(t *trie.Trie, kk key.KadKey, cpl int, depth int) (int, error) { } if depth == cpl { - return t.Size(), nil + // return the number of entries that do not share the next bit with kk + return t.Branch[1-kk.BitAt(depth)].Size(), nil } return countCpl(t.Branch[kk.BitAt(depth)], kk, cpl, depth+1) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 126b16c..dd05236 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -260,7 +260,7 @@ func TestCplSize(t *testing.T) { require.Equal(t, 2, rt.Size()) require.Equal(t, 2, rt.CplSize(2)) - require.Equal(t, 2, rt.CplSize(1)) + require.Equal(t, 0, rt.CplSize(1)) require.Equal(t, 0, rt.CplSize(3)) }) @@ -284,8 +284,8 @@ func TestCplSize(t *testing.T) { require.Equal(t, 4, rt.Size()) require.Equal(t, 4, rt.CplSize(3)) - require.Equal(t, 4, rt.CplSize(1)) - require.Equal(t, 4, rt.CplSize(2)) + require.Equal(t, 0, rt.CplSize(1)) + require.Equal(t, 0, rt.CplSize(2)) }) t.Run("cpl mixed", func(t *testing.T) { @@ -320,8 +320,8 @@ func TestCplSize(t *testing.T) { require.True(t, success) require.Equal(t, 8, rt.Size()) - require.Equal(t, 8, rt.CplSize(1)) - require.Equal(t, 6, rt.CplSize(2)) + require.Equal(t, 2, rt.CplSize(1)) + require.Equal(t, 2, rt.CplSize(2)) require.Equal(t, 4, rt.CplSize(3)) }) } From 9b99b49e021633cf83236370eea20a97c489bee4 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 12:07:55 +0100 Subject: [PATCH 12/32] Add trie implementation --- key/trie/trie.go | 211 ++++++++++++++++++++++++++++++++++++++++++ key/trie/trie_test.go | 180 +++++++++++++++++++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 key/trie/trie.go create mode 100644 key/trie/trie_test.go diff --git a/key/trie/trie.go b/key/trie/trie.go new file mode 100644 index 0000000..861a0ac --- /dev/null +++ b/key/trie/trie.go @@ -0,0 +1,211 @@ +package trie + +import ( + "encoding/json" + + "github.com/plprobelab/go-kademlia/key" +) + +// Trie is a trie for equal-length bit vectors, which stores values only in the leaves. +// Trie node invariants: +// (1) Either both branches are nil, or both are non-nil. +// (2) If branches are non-nil, key must be nil. +// (3) If both branches are leaves, then they are both non-empty (have keys). +type Trie[T any] struct { + Branch [2]*Trie[T] + Key key.KadKey + Data T +} + +func New[T any]() *Trie[T] { + return &Trie[T]{} +} + +func (trie *Trie[T]) String() string { + b, _ := json.Marshal(trie) + return string(b) +} + +func (trie *Trie[T]) Depth() int { + return trie.DepthAtDepth(0) +} + +func (trie *Trie[T]) DepthAtDepth(depth int) int { + if trie.Branch[0] == nil && trie.Branch[1] == nil { + return depth + } else { + return max(trie.Branch[0].DepthAtDepth(depth+1), trie.Branch[1].DepthAtDepth(depth+1)) + } +} + +func max(x, y int) int { + if x > y { + return x + } + return y +} + +// Size returns the number of keys added to the trie. +// In other words, it returns the number of non-empty leaves in the trie. +func (trie *Trie[T]) Size() int { + return trie.SizeAtDepth(0) +} + +func (trie *Trie[T]) SizeAtDepth(depth int) int { + if trie.Branch[0] == nil && trie.Branch[1] == nil { + if trie.IsEmpty() { + return 0 + } else { + return 1 + } + } else { + return trie.Branch[0].SizeAtDepth(depth+1) + trie.Branch[1].SizeAtDepth(depth+1) + } +} + +func (trie *Trie[T]) IsEmpty() bool { + return trie.Key == nil +} + +func (trie *Trie[T]) IsLeaf() bool { + return trie.Branch[0] == nil && trie.Branch[1] == nil +} + +func (trie *Trie[T]) IsEmptyLeaf() bool { + return trie.IsEmpty() && trie.IsLeaf() +} + +func (trie *Trie[T]) IsNonEmptyLeaf() bool { + return !trie.IsEmpty() && trie.IsLeaf() +} + +func (trie *Trie[T]) Copy() *Trie[T] { + if trie.IsLeaf() { + return &Trie[T]{Key: trie.Key} + } + + return &Trie[T]{Branch: [2]*Trie[T]{ + trie.Branch[0].Copy(), + trie.Branch[1].Copy(), + }} +} + +func (trie *Trie[T]) shrink() { + b0, b1 := trie.Branch[0], trie.Branch[1] + switch { + case b0.IsEmptyLeaf() && b1.IsEmptyLeaf(): + trie.Branch[0], trie.Branch[1] = nil, nil + case b0.IsEmptyLeaf() && b1.IsNonEmptyLeaf(): + trie.Key = b1.Key + trie.Branch[0], trie.Branch[1] = nil, nil + case b0.IsNonEmptyLeaf() && b1.IsEmptyLeaf(): + trie.Key = b0.Key + trie.Branch[0], trie.Branch[1] = nil, nil + } +} + +// Add adds the key q to trie, returning a new trie. +// Add is immutable/non-destructive: The original trie remains unchanged. +func Add[T any](trie *Trie[T], q key.KadKey) (*Trie[T], error) { + return AddAtDepth(0, trie, q) +} + +func AddAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], error) { + switch { + case trie.IsEmptyLeaf(): + return &Trie[T]{Key: q}, nil + case trie.IsNonEmptyLeaf(): + eq, err := trie.Key.Equal(q) + if err != nil { + return nil, err + } + if eq { + return trie, nil + } + return trieForTwo[T](depth, trie.Key, q), nil + + default: + dir := q.BitAt(depth) + s := &Trie[T]{} + b, err := AddAtDepth(depth+1, trie.Branch[dir], q) + if err != nil { + return nil, err + } + s.Branch[dir] = b + s.Branch[1-dir] = trie.Branch[1-dir] + return s, nil + } +} + +func trieForTwo[T any](depth int, p, q key.KadKey) *Trie[T] { + pDir, qDir := p.BitAt(depth), q.BitAt(depth) + if qDir == pDir { + s := &Trie[T]{} + s.Branch[pDir] = trieForTwo[T](depth+1, p, q) + s.Branch[1-pDir] = &Trie[T]{} + return s + } else { + s := &Trie[T]{} + s.Branch[pDir] = &Trie[T]{Key: p} + s.Branch[qDir] = &Trie[T]{Key: q} + return s + } +} + +func Remove[T any](trie *Trie[T], q key.KadKey) (*Trie[T], error) { + return RemoveAtDepth(0, trie, q) +} + +func RemoveAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], error) { + switch { + case trie.IsEmptyLeaf(): + return trie, nil + case trie.IsNonEmptyLeaf(): + eq, err := trie.Key.Equal(q) + if err != nil { + return nil, err + } + if !eq { + return trie, nil + } + return &Trie[T]{}, nil + + default: + dir := q.BitAt(depth) + b, err := RemoveAtDepth(depth+1, trie.Branch[dir], q) + if err != nil { + return nil, err + } + afterDelete := b + if afterDelete == trie.Branch[dir] { + return trie, nil + } + copy := &Trie[T]{} + copy.Branch[dir] = afterDelete + copy.Branch[1-dir] = trie.Branch[1-dir] + copy.shrink() + return copy, nil + } +} + +// Find looks for the key q in the trie. +// It returns the depth of the leaf reached along the path of q, regardless of whether q was found in that leaf. +// It also returns a boolean flag indicating whether the key was found. +func Find[T any](trie *Trie[T], q key.KadKey) (int, bool, error) { + return FindAtDepth(trie, 0, q) +} + +func FindAtDepth[T any](trie *Trie[T], depth int, q key.KadKey) (int, bool, error) { + switch { + case trie.IsEmptyLeaf(): + return depth, false, nil + case trie.IsNonEmptyLeaf(): + eq, err := trie.Key.Equal(q) + if err != nil { + return depth, false, err + } + return depth, eq, nil + default: + return FindAtDepth(trie.Branch[q.BitAt(depth)], depth+1, q) + } +} diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go new file mode 100644 index 0000000..3e80863 --- /dev/null +++ b/key/trie/trie_test.go @@ -0,0 +1,180 @@ +package trie + +import ( + "testing" + + "github.com/plprobelab/go-kademlia/key" +) + +func FromKeys[T any](kks []key.KadKey) (*Trie[T], error) { + t := New[T]() + var err error + for _, kk := range kks { + t, err = Add(t, kk) + if err != nil { + return nil, err + } + } + return t, nil +} + +func TestInsertRemove(t *testing.T) { + r := New[any]() + testSeq(r, t) + testSeq(r, t) +} + +func testSeq[T any](tr *Trie[T], t *testing.T) { + var err error + for _, s := range testInsertSeq { + tr, err = Add(tr, s.key) + if err != nil { + t.Fatalf("unexpected error during add: %v", err) + } + depth, found, err := Find(tr, s.key) + if err != nil { + t.Fatalf("unexpected error during find: %v", err) + } + if !found { + t.Fatalf("key not found: %v", s.key) + } + if depth != s.insertedDepth { + t.Errorf("inserting expected depth %d, got %d", s.insertedDepth, depth) + } + } + for _, s := range testRemoveSeq { + tr, err = Remove(tr, s.key) + if err != nil { + t.Fatalf("unexpected error during remove: %v", err) + } + depth, found, err := Find(tr, s.key) + if err != nil { + t.Fatalf("unexpected error during find: %v", err) + } + if found { + t.Fatalf("key unexpectedly found: %v", s.key) + } + if depth != s.reachedDepth { + t.Errorf("removing key %q expected depth %d, got %d", s.key, s.reachedDepth, depth) + } + } +} + +func TestCopy(t *testing.T) { + for _, sample := range testAddSamples { + trie, err := FromKeys[any](sample.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + copy := trie.Copy() + if d := copy.CheckInvariant(); d != nil { + t.Fatalf("trie invariant discrepancy: %v", d) + } + if trie == copy { + t.Errorf("Expected trie copy not to be the same reference as original") + } + if !Equal(trie, copy) { + t.Errorf("Expected tries to be equal, original: %v\n, copy: %v\n", trie, copy) + } + } +} + +var testInsertSeq = []struct { + key key.KadKey + insertedDepth int +}{ + {key: key.KadKey([]byte{0x00}), insertedDepth: 0}, + {key: key.KadKey([]byte{0x80}), insertedDepth: 1}, + {key: key.KadKey([]byte{0x10}), insertedDepth: 4}, + {key: key.KadKey([]byte{0xc0}), insertedDepth: 2}, + {key: key.KadKey([]byte{0x20}), insertedDepth: 3}, +} + +var testRemoveSeq = []struct { + key key.KadKey + reachedDepth int +}{ + {key: key.KadKey([]byte{0x00}), reachedDepth: 4}, + {key: key.KadKey([]byte{0x10}), reachedDepth: 3}, + {key: key.KadKey([]byte{0x20}), reachedDepth: 1}, + {key: key.KadKey([]byte{0x80}), reachedDepth: 2}, + {key: key.KadKey([]byte{0xc0}), reachedDepth: 0}, +} + +// // Verify mutable and immutable add do the same thing. +// func TestMutableAndImmutableAddSame(t *testing.T) { +// for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { +// mut := New[any]() +// immut := New[any]() +// for _, k := range s.Keys { +// mut.Add(k) +// immut = Add(immut, k) +// } +// if d := mut.CheckInvariant(); d != nil { +// t.Fatalf("mutable trie invariant discrepancy: %v", d) +// } +// if d := immut.CheckInvariant(); d != nil { +// t.Fatalf("immutable trie invariant discrepancy: %v", d) +// } +// if !Equal(mut, immut) { +// t.Errorf("mutable trie %v differs from immutable trie %v", mut, immut) +// } +// } +// } + +// func TestAddIsOrderIndependent(t *testing.T) { +// for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { +// base := New[any]() +// for _, k := range s.Keys { +// base.Add(k) +// } +// if d := base.CheckInvariant(); d != nil { +// t.Fatalf("base trie invariant discrepancy: %v", d) +// } +// for j := 0; j < 100; j++ { +// perm := rand.Perm(len(s.Keys)) +// reordered := New[any]() +// for i := range s.Keys { +// reordered.Add(s.Keys[perm[i]]) +// } +// if d := reordered.CheckInvariant(); d != nil { +// t.Fatalf("reordered trie invariant discrepancy: %v", d) +// } +// if !Equal(base, reordered) { +// t.Errorf("trie %v differs from trie %v", base, reordered) +// } +// } +// } +// } + +// type testAddSample struct { +// Keys []key.KadKey +// } + +// var testAddSamples = []*testAddSample{ +// {Keys: []key.KadKey{key.ByteKey(1), key.ByteKey(3), key.ByteKey(5), key.ByteKey(7), key.ByteKey(11), key.ByteKey(13)}}, +// {Keys: []key.KadKey{ +// key.ByteKey(11), key.ByteKey(22), key.ByteKey(23), key.ByteKey(25), +// key.ByteKey(27), key.ByteKey(28), key.ByteKey(31), key.ByteKey(32), key.ByteKey(33), +// }}, +// } + +// func randomTestAddSamples(count int) []*testAddSample { +// s := make([]*testAddSample, count) +// for i := range s { +// s[i] = randomTestAddSample(31, 2) +// } +// return s +// } + +// func randomTestAddSample(setSize, keySizeByte int) *testAddSample { +// keySet := make([]key.KadKey, setSize) +// for i := range keySet { +// k := make([]byte, keySizeByte) +// rand.Read(k) +// keySet[i] = key.BytesKey(k) +// } +// return &testAddSample{ +// Keys: keySet, +// } +// } From e882e36f8d994860ce157f14952298da20101496 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:40:22 +0100 Subject: [PATCH 13/32] Add trie implementation --- key/errors.go | 12 ++ key/key.go | 11 ++ key/trie/trie.go | 74 ++++++----- key/trie/trie_test.go | 281 +++++++++++++++++++++++++++------------- routing/triert/table.go | 107 ++++++--------- 5 files changed, 296 insertions(+), 189 deletions(-) create mode 100644 key/errors.go diff --git a/key/errors.go b/key/errors.go new file mode 100644 index 0000000..0c58ab0 --- /dev/null +++ b/key/errors.go @@ -0,0 +1,12 @@ +package key + +import ( + "errors" + "fmt" +) + +var ErrKeyWrongLength = errors.New("key has wrong length") + +func ErrInvalidKey(l int) error { + return fmt.Errorf("invalid key: should be %d bytes long", l) +} diff --git a/key/key.go b/key/key.go index 253b0d1..3e41188 100644 --- a/key/key.go +++ b/key/key.go @@ -2,7 +2,9 @@ package key import ( "encoding/hex" + "fmt" "math" + "strings" ) type KadKey []byte @@ -26,6 +28,15 @@ func shortLong(a, b KadKey) (min, max KadKey) { return b, a } +// BitString returns a bit representation of the key, in descending order of significance. +func (k KadKey) BitString() string { + sb := new(strings.Builder) + for _, b := range k { + sb.WriteString(fmt.Sprintf("%08b", b)) + } + return sb.String() +} + func (a KadKey) Xor(b KadKey) KadKey { short, long := shortLong(a, b) xored := make([]byte, len(long)) diff --git a/key/trie/trie.go b/key/trie/trie.go index 861a0ac..061c321 100644 --- a/key/trie/trie.go +++ b/key/trie/trie.go @@ -81,7 +81,7 @@ func (trie *Trie[T]) IsNonEmptyLeaf() bool { func (trie *Trie[T]) Copy() *Trie[T] { if trie.IsLeaf() { - return &Trie[T]{Key: trie.Key} + return &Trie[T]{Key: trie.Key, Data: trie.Data} } return &Trie[T]{Branch: [2]*Trie[T]{ @@ -104,30 +104,27 @@ func (trie *Trie[T]) shrink() { } } -// Add adds the key q to trie, returning a new trie. +// Add adds the key to trie, returning a new trie. // Add is immutable/non-destructive: The original trie remains unchanged. -func Add[T any](trie *Trie[T], q key.KadKey) (*Trie[T], error) { - return AddAtDepth(0, trie, q) +func Add[T any](trie *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { + return AddAtDepth(0, trie, kk, data) } -func AddAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], error) { +func AddAtDepth[T any](depth int, trie *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { switch { case trie.IsEmptyLeaf(): - return &Trie[T]{Key: q}, nil + return &Trie[T]{Key: kk, Data: data}, nil case trie.IsNonEmptyLeaf(): - eq, err := trie.Key.Equal(q) - if err != nil { - return nil, err - } + eq := trie.Key.Equal(kk) if eq { return trie, nil } - return trieForTwo[T](depth, trie.Key, q), nil + return trieForTwo[T](depth, trie.Key, trie.Data, kk, data), nil default: - dir := q.BitAt(depth) + dir := kk.BitAt(depth) s := &Trie[T]{} - b, err := AddAtDepth(depth+1, trie.Branch[dir], q) + b, err := AddAtDepth(depth+1, trie.Branch[dir], kk, data) if err != nil { return nil, err } @@ -137,17 +134,17 @@ func AddAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], error) } } -func trieForTwo[T any](depth int, p, q key.KadKey) *Trie[T] { +func trieForTwo[T any](depth int, p key.KadKey, pdata T, q key.KadKey, qdata T) *Trie[T] { pDir, qDir := p.BitAt(depth), q.BitAt(depth) if qDir == pDir { s := &Trie[T]{} - s.Branch[pDir] = trieForTwo[T](depth+1, p, q) + s.Branch[pDir] = trieForTwo[T](depth+1, p, pdata, q, qdata) s.Branch[1-pDir] = &Trie[T]{} return s } else { s := &Trie[T]{} - s.Branch[pDir] = &Trie[T]{Key: p} - s.Branch[qDir] = &Trie[T]{Key: q} + s.Branch[pDir] = &Trie[T]{Key: p, Data: pdata} + s.Branch[qDir] = &Trie[T]{Key: q, Data: qdata} return s } } @@ -161,10 +158,7 @@ func RemoveAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], err case trie.IsEmptyLeaf(): return trie, nil case trie.IsNonEmptyLeaf(): - eq, err := trie.Key.Equal(q) - if err != nil { - return nil, err - } + eq := trie.Key.Equal(q) if !eq { return trie, nil } @@ -188,24 +182,36 @@ func RemoveAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], err } } -// Find looks for the key q in the trie. -// It returns the depth of the leaf reached along the path of q, regardless of whether q was found in that leaf. -// It also returns a boolean flag indicating whether the key was found. -func Find[T any](trie *Trie[T], q key.KadKey) (int, bool, error) { - return FindAtDepth(trie, 0, q) +func Equal[T any](p, q *Trie[T]) bool { + switch { + case p.IsLeaf() && q.IsLeaf(): + eq := p.Key.Equal(q.Key) + if !eq { + return false + } + return true + case !p.IsLeaf() && !q.IsLeaf(): + return Equal(p.Branch[0], q.Branch[0]) && Equal(p.Branch[1], q.Branch[1]) + } + return false } -func FindAtDepth[T any](trie *Trie[T], depth int, q key.KadKey) (int, bool, error) { +// Find looks for the key in the trie. +// It reports whether the key was found along with the depth of the leaf reached along the path +// of the key, regardless of whether the key was found in that leaf. +func Find[T any](trie *Trie[T], kk key.KadKey) (bool, T, int) { + return FindAtDepth(trie, 0, kk) +} + +func FindAtDepth[T any](trie *Trie[T], depth int, kk key.KadKey) (bool, T, int) { switch { case trie.IsEmptyLeaf(): - return depth, false, nil + var v T + return false, v, depth case trie.IsNonEmptyLeaf(): - eq, err := trie.Key.Equal(q) - if err != nil { - return depth, false, err - } - return depth, eq, nil + eq := trie.Key.Equal(kk) + return eq, trie.Data, depth default: - return FindAtDepth(trie.Branch[q.BitAt(depth)], depth+1, q) + return FindAtDepth(trie.Branch[kk.BitAt(depth)], depth+1, kk) } } diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 3e80863..a0883d1 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -1,6 +1,7 @@ package trie import ( + "math/rand" "testing" "github.com/plprobelab/go-kademlia/key" @@ -10,7 +11,8 @@ func FromKeys[T any](kks []key.KadKey) (*Trie[T], error) { t := New[T]() var err error for _, kk := range kks { - t, err = Add(t, kk) + var v T + t, err = Add(t, kk, v) if err != nil { return nil, err } @@ -27,35 +29,33 @@ func TestInsertRemove(t *testing.T) { func testSeq[T any](tr *Trie[T], t *testing.T) { var err error for _, s := range testInsertSeq { - tr, err = Add(tr, s.key) + var v T + tr, err = Add(tr, s.key, v) if err != nil { t.Fatalf("unexpected error during add: %v", err) } - depth, found, err := Find(tr, s.key) - if err != nil { - t.Fatalf("unexpected error during find: %v", err) - } + found, _, depth := Find(tr, s.key) if !found { t.Fatalf("key not found: %v", s.key) } if depth != s.insertedDepth { t.Errorf("inserting expected depth %d, got %d", s.insertedDepth, depth) } + if d := CheckInvariant(tr); d != nil { + t.Fatalf("trie invariant discrepancy: %v", d) + } } for _, s := range testRemoveSeq { tr, err = Remove(tr, s.key) if err != nil { t.Fatalf("unexpected error during remove: %v", err) } - depth, found, err := Find(tr, s.key) - if err != nil { - t.Fatalf("unexpected error during find: %v", err) - } + found, _, _ := Find(tr, s.key) if found { t.Fatalf("key unexpectedly found: %v", s.key) } - if depth != s.reachedDepth { - t.Errorf("removing key %q expected depth %d, got %d", s.key, s.reachedDepth, depth) + if d := CheckInvariant(tr); d != nil { + t.Fatalf("trie invariant discrepancy: %v", d) } } } @@ -67,7 +67,7 @@ func TestCopy(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } copy := trie.Copy() - if d := copy.CheckInvariant(); d != nil { + if d := CheckInvariant(copy); d != nil { t.Fatalf("trie invariant discrepancy: %v", d) } if trie == copy { @@ -101,80 +101,181 @@ var testRemoveSeq = []struct { {key: key.KadKey([]byte{0xc0}), reachedDepth: 0}, } -// // Verify mutable and immutable add do the same thing. -// func TestMutableAndImmutableAddSame(t *testing.T) { -// for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { -// mut := New[any]() -// immut := New[any]() -// for _, k := range s.Keys { -// mut.Add(k) -// immut = Add(immut, k) -// } -// if d := mut.CheckInvariant(); d != nil { -// t.Fatalf("mutable trie invariant discrepancy: %v", d) -// } -// if d := immut.CheckInvariant(); d != nil { -// t.Fatalf("immutable trie invariant discrepancy: %v", d) -// } -// if !Equal(mut, immut) { -// t.Errorf("mutable trie %v differs from immutable trie %v", mut, immut) -// } -// } -// } - -// func TestAddIsOrderIndependent(t *testing.T) { -// for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { -// base := New[any]() -// for _, k := range s.Keys { -// base.Add(k) -// } -// if d := base.CheckInvariant(); d != nil { -// t.Fatalf("base trie invariant discrepancy: %v", d) -// } -// for j := 0; j < 100; j++ { -// perm := rand.Perm(len(s.Keys)) -// reordered := New[any]() -// for i := range s.Keys { -// reordered.Add(s.Keys[perm[i]]) -// } -// if d := reordered.CheckInvariant(); d != nil { -// t.Fatalf("reordered trie invariant discrepancy: %v", d) -// } -// if !Equal(base, reordered) { -// t.Errorf("trie %v differs from trie %v", base, reordered) -// } -// } -// } -// } - -// type testAddSample struct { -// Keys []key.KadKey -// } - -// var testAddSamples = []*testAddSample{ -// {Keys: []key.KadKey{key.ByteKey(1), key.ByteKey(3), key.ByteKey(5), key.ByteKey(7), key.ByteKey(11), key.ByteKey(13)}}, -// {Keys: []key.KadKey{ -// key.ByteKey(11), key.ByteKey(22), key.ByteKey(23), key.ByteKey(25), -// key.ByteKey(27), key.ByteKey(28), key.ByteKey(31), key.ByteKey(32), key.ByteKey(33), -// }}, -// } - -// func randomTestAddSamples(count int) []*testAddSample { -// s := make([]*testAddSample, count) -// for i := range s { -// s[i] = randomTestAddSample(31, 2) -// } -// return s -// } - -// func randomTestAddSample(setSize, keySizeByte int) *testAddSample { -// keySet := make([]key.KadKey, setSize) -// for i := range keySet { -// k := make([]byte, keySizeByte) -// rand.Read(k) -// keySet[i] = key.BytesKey(k) -// } -// return &testAddSample{ -// Keys: keySet, -// } -// } +func TestAddIsOrderIndependent(t *testing.T) { + for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { + base := New[any]() + for _, k := range s.Keys { + base, _ = Add(base, k, nil) + } + if d := CheckInvariant(base); d != nil { + t.Fatalf("base trie invariant discrepancy: %v", d) + } + for j := 0; j < 100; j++ { + perm := rand.Perm(len(s.Keys)) + reordered := New[any]() + for i := range s.Keys { + reordered, _ = Add(reordered, s.Keys[perm[i]], nil) + } + if d := CheckInvariant(reordered); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } + if !Equal(base, reordered) { + t.Errorf("trie %v differs from trie %v", base, reordered) + } + } + } +} + +type testAddSample struct { + Keys []key.KadKey +} + +var testAddSamples = []*testAddSample{ + {Keys: []key.KadKey{[]byte{1}, []byte{3}, []byte{5}, []byte{7}, []byte{11}, []byte{13}}}, + {Keys: []key.KadKey{ + []byte{11}, + []byte{22}, + []byte{23}, + []byte{25}, + []byte{27}, + []byte{28}, + []byte{31}, + []byte{32}, + []byte{33}, + }}, +} + +func randomTestAddSamples(count int) []*testAddSample { + s := make([]*testAddSample, count) + for i := range s { + s[i] = randomTestAddSample(31, 2) + } + return s +} + +func randomTestAddSample(setSize, keySizeByte int) *testAddSample { + keySet := make([]key.KadKey, setSize) + for i := range keySet { + k := make([]byte, keySizeByte) + rand.Read(k) + keySet[i] = key.KadKey(k) + } + return &testAddSample{ + Keys: keySet, + } +} + +type InvariantDiscrepancy struct { + Reason string + PathToDiscrepancy string + KeyAtDiscrepancy string +} + +// CheckInvariant panics of the trie does not meet its invariant. +func CheckInvariant[T any](trie *Trie[T]) *InvariantDiscrepancy { + return checkInvariant(trie, 0, nil) +} + +func checkInvariant[T any](trie *Trie[T], depth int, pathSoFar *triePath) *InvariantDiscrepancy { + switch { + case trie.IsEmptyLeaf(): + return nil + case trie.IsNonEmptyLeaf(): + if !pathSoFar.matchesKey(trie.Key) { + return &InvariantDiscrepancy{ + Reason: "key found at invalid location in trie", + PathToDiscrepancy: pathSoFar.BitString(), + KeyAtDiscrepancy: trie.Key.BitString(), + } + } + return nil + default: + if trie.IsEmpty() { + b0, b1 := trie.Branch[0], trie.Branch[1] + if d0 := checkInvariant(b0, depth+1, pathSoFar.Push(0)); d0 != nil { + return d0 + } + if d1 := checkInvariant(b1, depth+1, pathSoFar.Push(1)); d1 != nil { + return d1 + } + switch { + case b0.IsEmptyLeaf() && b1.IsEmptyLeaf(): + return &InvariantDiscrepancy{ + Reason: "intermediate node with two empty leaves", + PathToDiscrepancy: pathSoFar.BitString(), + KeyAtDiscrepancy: "none", + } + case b0.IsEmptyLeaf() && b1.IsNonEmptyLeaf(): + return &InvariantDiscrepancy{ + Reason: "intermediate node with one empty leaf/0", + PathToDiscrepancy: pathSoFar.BitString(), + KeyAtDiscrepancy: "none", + } + case b0.IsNonEmptyLeaf() && b1.IsEmptyLeaf(): + return &InvariantDiscrepancy{ + Reason: "intermediate node with one empty leaf/1", + PathToDiscrepancy: pathSoFar.BitString(), + KeyAtDiscrepancy: "none", + } + default: + return nil + } + } else { + return &InvariantDiscrepancy{ + Reason: "intermediate node with a key", + PathToDiscrepancy: pathSoFar.BitString(), + KeyAtDiscrepancy: trie.Key.BitString(), + } + } + } +} + +type triePath struct { + parent *triePath + bit byte +} + +func (p *triePath) Push(bit byte) *triePath { + return &triePath{parent: p, bit: bit} +} + +func (p *triePath) RootPath() []byte { + if p == nil { + return nil + } else { + return append(p.parent.RootPath(), p.bit) + } +} + +func (p *triePath) matchesKey(k key.KadKey) bool { + ok, _ := p.walk(k, 0) + return ok +} + +func (p *triePath) walk(k key.KadKey, depthToLeaf int) (ok bool, depthToRoot int) { + if p == nil { + return true, 0 + } else { + parOk, parDepthToRoot := p.parent.walk(k, depthToLeaf+1) + return k.BitAt(parDepthToRoot) == int(p.bit) && parOk, parDepthToRoot + 1 + } +} + +func (p *triePath) BitString() string { + return p.bitString(0) +} + +func (p *triePath) bitString(depthToLeaf int) string { + if p == nil { + return "" + } else { + switch { + case p.bit == 0: + return p.parent.bitString(depthToLeaf+1) + "0" + case p.bit == 1: + return p.parent.bitString(depthToLeaf+1) + "1" + default: + panic("bit digit > 1") + } + } +} diff --git a/routing/triert/table.go b/routing/triert/table.go index 8e90e10..750f7cb 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -6,9 +6,8 @@ import ( "sync" "sync/atomic" - tkey "github.com/libp2p/go-libp2p-xor/key" - "github.com/libp2p/go-libp2p-xor/trie" "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" ) @@ -21,25 +20,21 @@ var ErrKeyWrongLength = errors.New("key has wrong length") type TrieRT struct { self key.KadKey - // keymu is held during keys and keyNodes mutations to serialize changes + // keymu is held during trie mutations to serialize changes keymu sync.Mutex // keys holds a pointer to an immutable trie // any store to keys must be performed while holding keymu, loads may be performed without the lock keys atomic.Value - - // keyNodes holds a mapping of kademlia key to node id (map[string]address.NodeID) - // note: this could be eliminated if the trie was modified to allow a tuple to be stored at each node - // any store to keyNodes must be performed while holding keymu, loads may be performed without the lock - keyNodes atomic.Value } +type nodeTrie = trie.Trie[address.NodeID] + func New(self key.KadKey) *TrieRT { rt := &TrieRT{ self: self, } - rt.keys.Store(&trie.Trie{}) - rt.keyNodes.Store(map[string]address.NodeID{}) + rt.keys.Store(&nodeTrie{}) return rt } @@ -57,24 +52,16 @@ func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error rt.keymu.Lock() defer rt.keymu.Unlock() // load the old trie, derive a mutated variant and store it in place of the original - keys := rt.keys.Load().(*trie.Trie) - keysNext := trie.Add(keys, tkey.Key(kk)) + keys := rt.keys.Load().(*nodeTrie) + keysNext, err := trie.Add(keys, kk, node) + if err != nil { + return false, err + } // if trie is unchanged then we didn't add the key if keysNext == keys { return false, nil } - - // make a copy of keyNodes - // could avoid this if we held key/nodeid tuple in the trie - keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) - keyNodesNext := make(map[string]address.NodeID, len(keyNodes)+1) - for k, v := range keyNodes { - keyNodesNext[k] = v - } - keyNodesNext[string(kk)] = node - - rt.keyNodes.Store(keyNodesNext) rt.keys.Store(keysNext) return true, nil } @@ -88,28 +75,16 @@ func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { rt.keymu.Lock() defer rt.keymu.Unlock() // load the old trie, derive a mutated variant and store it in place of the original - keys := rt.keys.Load().(*trie.Trie) - keysNext := trie.Remove(keys, tkey.Key(kk)) - + keys := rt.keys.Load().(*nodeTrie) + keysNext, err := trie.Remove(keys, kk) + if err != nil { + return false, err + } // if trie is unchanged then we didn't remove the key if keysNext == keys { return false, nil } - // make a copy of keyNodes without removed key - // could avoid this if we held key/nodeid tuple in the trie - keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) - if _, exists := keyNodes[string(kk)]; exists { - keyNodesNext := make(map[string]address.NodeID, len(keyNodes)) - for k, v := range keyNodes { - if k == string(kk) { - continue - } - keyNodesNext[k] = v - } - rt.keyNodes.Store(keyNodesNext) - } - rt.keys.Store(keysNext) return true, nil } @@ -120,42 +95,45 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add return nil, ErrKeyWrongLength } - keys := rt.keys.Load().(*trie.Trie) - closestKeys := closestAtDepth(tkey.Key(kk), keys, 0, n) - if len(closestKeys) == 0 { + keys := rt.keys.Load().(*nodeTrie) + closestEntries := closestAtDepth(kk, keys, 0, n) + if len(closestEntries) == 0 { return []address.NodeID{}, nil } - keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) - - nodes := make([]address.NodeID, 0, len(closestKeys)) - for _, c := range closestKeys { - if id, ok := keyNodes[string(key.KadKey(c))]; ok { - nodes = append(nodes, id) - } + nodes := make([]address.NodeID, 0, len(closestEntries)) + for _, c := range closestEntries { + nodes = append(nodes, c.Data) } return nodes, nil } -func closestAtDepth(k tkey.Key, t *trie.Trie, depth int, n int) []tkey.Key { +type entry struct { + Key key.KadKey + Data address.NodeID +} + +func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { if t.Key != nil { // We've found a leaf - return []tkey.Key{t.Key} + return []entry{ + {Key: t.Key, Data: t.Data}, + } } else if t.Branch[0] == nil && t.Branch[1] == nil { // We've found an empty node? return nil } // Find the closest direction. - dir := k.BitAt(depth) + dir := kk.BitAt(depth) // Add peers from the closest direction first - found := closestAtDepth(k, t.Branch[dir], depth+1, n) + found := closestAtDepth(kk, t.Branch[dir], depth+1, n) if len(found) == n { return found } // Didn't find enough peers in the closest direction, try the other direction. - return append(found, closestAtDepth(k, t.Branch[1-dir], depth+1, n-len(found))...) + return append(found, closestAtDepth(kk, t.Branch[1-dir], depth+1, n-len(found))...) } func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { @@ -163,10 +141,12 @@ func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, erro return nil, ErrKeyWrongLength } - keyNodes := rt.keyNodes.Load().(map[string]address.NodeID) + keys := rt.keys.Load().(*nodeTrie) - if id, ok := keyNodes[string(key.KadKey(kk))]; ok { - return id, nil + found, node, _ := trie.Find(keys, kk) + + if found { + return node, nil } return nil, nil @@ -174,13 +154,13 @@ func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, erro // Size returns the number of peers contained in the table. func (rt *TrieRT) Size() int { - keys := rt.keys.Load().(*trie.Trie) + keys := rt.keys.Load().(*nodeTrie) return keys.Size() } // CplSize returns the number of peers in the table whose longest common prefix with the table's key is of length cpl. func (rt *TrieRT) CplSize(cpl int) int { - keys := rt.keys.Load().(*trie.Trie) + keys := rt.keys.Load().(*nodeTrie) n, err := countCpl(keys, rt.self, cpl, 0) if err != nil { return 0 @@ -188,16 +168,13 @@ func (rt *TrieRT) CplSize(cpl int) int { return n } -func countCpl(t *trie.Trie, kk key.KadKey, cpl int, depth int) (int, error) { +func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { // special cases for very small tables where keys may be placed higher in the trie due to low population if t.IsLeaf() { if t.IsEmpty() { return 0, nil } - keyCpl, err := kk.CommonPrefixLength(key.KadKey(t.Key)) - if err != nil { - return 0, err - } + keyCpl := kk.CommonPrefixLength(key.KadKey(t.Key)) if keyCpl == cpl { return 1, nil } From 535956b24d2f482a59bedf430bbd0ac5d43d8d9d Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:09:18 +0100 Subject: [PATCH 14/32] Tidy up trie package --- key/errors.go | 3 - key/trie/README.md | 3 + key/trie/trie.go | 183 ++++++++++++++++++++--------------- key/trie/trie_test.go | 28 +++--- routing/triert/table.go | 17 ++-- routing/triert/table_test.go | 9 +- 6 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 key/trie/README.md diff --git a/key/errors.go b/key/errors.go index 0c58ab0..6fb9a39 100644 --- a/key/errors.go +++ b/key/errors.go @@ -1,12 +1,9 @@ package key import ( - "errors" "fmt" ) -var ErrKeyWrongLength = errors.New("key has wrong length") - func ErrInvalidKey(l int) error { return fmt.Errorf("invalid key: should be %d bytes long", l) } diff --git a/key/trie/README.md b/key/trie/README.md new file mode 100644 index 0000000..db342a7 --- /dev/null +++ b/key/trie/README.md @@ -0,0 +1,3 @@ +# Trie + +This package contains an implementation of a XOR Trie. diff --git a/key/trie/trie.go b/key/trie/trie.go index 061c321..78fa191 100644 --- a/key/trie/trie.go +++ b/key/trie/trie.go @@ -1,12 +1,16 @@ +// Package trie provides an implementation of a XOR Trie package trie import ( - "encoding/json" + "errors" "github.com/plprobelab/go-kademlia/key" ) +var ErrMismatchedKeyLength = errors.New("key length does not match existing keys") + // Trie is a trie for equal-length bit vectors, which stores values only in the leaves. +// A node may optionally hold data of type T // Trie node invariants: // (1) Either both branches are nil, or both are non-nil. // (2) If branches are non-nil, key must be nil. @@ -21,20 +25,17 @@ func New[T any]() *Trie[T] { return &Trie[T]{} } -func (trie *Trie[T]) String() string { - b, _ := json.Marshal(trie) - return string(b) -} - -func (trie *Trie[T]) Depth() int { - return trie.DepthAtDepth(0) +// Depth returns the maximum depth of the Trie. +func (tr *Trie[T]) Depth() int { + return tr.DepthAtDepth(0) } -func (trie *Trie[T]) DepthAtDepth(depth int) int { - if trie.Branch[0] == nil && trie.Branch[1] == nil { - return depth +// Depth returns the maximum depth at or beyond depth d. +func (tr *Trie[T]) DepthAtDepth(d int) int { + if tr.IsLeaf() { + return d } else { - return max(trie.Branch[0].DepthAtDepth(depth+1), trie.Branch[1].DepthAtDepth(depth+1)) + return max(tr.Branch[0].DepthAtDepth(d+1), tr.Branch[1].DepthAtDepth(d+1)) } } @@ -46,90 +47,95 @@ func max(x, y int) int { } // Size returns the number of keys added to the trie. -// In other words, it returns the number of non-empty leaves in the trie. -func (trie *Trie[T]) Size() int { - return trie.SizeAtDepth(0) +func (tr *Trie[T]) Size() int { + return tr.SizeAtDepth(0) } -func (trie *Trie[T]) SizeAtDepth(depth int) int { - if trie.Branch[0] == nil && trie.Branch[1] == nil { - if trie.IsEmpty() { +// Size returns the number of keys added to the trie at or beyond depth d. +func (tr *Trie[T]) SizeAtDepth(d int) int { + if tr.IsLeaf() { + if !tr.HasKey() { return 0 } else { return 1 } } else { - return trie.Branch[0].SizeAtDepth(depth+1) + trie.Branch[1].SizeAtDepth(depth+1) + return tr.Branch[0].SizeAtDepth(d+1) + tr.Branch[1].SizeAtDepth(d+1) } } -func (trie *Trie[T]) IsEmpty() bool { - return trie.Key == nil +// HasKey reports whether the Trie node holds a key. +func (tr *Trie[T]) HasKey() bool { + return tr.Key != nil } -func (trie *Trie[T]) IsLeaf() bool { - return trie.Branch[0] == nil && trie.Branch[1] == nil +// IsLeaf reports whether the Trie is a leaf node. A leaf node has no child branches but may hold a key and data. +func (tr *Trie[T]) IsLeaf() bool { + return tr.Branch[0] == nil && tr.Branch[1] == nil } -func (trie *Trie[T]) IsEmptyLeaf() bool { - return trie.IsEmpty() && trie.IsLeaf() +func (tr *Trie[T]) IsEmptyLeaf() bool { + return !tr.HasKey() && tr.IsLeaf() } -func (trie *Trie[T]) IsNonEmptyLeaf() bool { - return !trie.IsEmpty() && trie.IsLeaf() +func (tr *Trie[T]) IsNonEmptyLeaf() bool { + return tr.HasKey() && tr.IsLeaf() } -func (trie *Trie[T]) Copy() *Trie[T] { - if trie.IsLeaf() { - return &Trie[T]{Key: trie.Key, Data: trie.Data} +func (tr *Trie[T]) Copy() *Trie[T] { + if tr.IsLeaf() { + return &Trie[T]{Key: tr.Key, Data: tr.Data} } return &Trie[T]{Branch: [2]*Trie[T]{ - trie.Branch[0].Copy(), - trie.Branch[1].Copy(), + tr.Branch[0].Copy(), + tr.Branch[1].Copy(), }} } -func (trie *Trie[T]) shrink() { - b0, b1 := trie.Branch[0], trie.Branch[1] +func (tr *Trie[T]) shrink() { + b0, b1 := tr.Branch[0], tr.Branch[1] switch { case b0.IsEmptyLeaf() && b1.IsEmptyLeaf(): - trie.Branch[0], trie.Branch[1] = nil, nil + tr.Branch[0], tr.Branch[1] = nil, nil case b0.IsEmptyLeaf() && b1.IsNonEmptyLeaf(): - trie.Key = b1.Key - trie.Branch[0], trie.Branch[1] = nil, nil + tr.Key = b1.Key + tr.Branch[0], tr.Branch[1] = nil, nil case b0.IsNonEmptyLeaf() && b1.IsEmptyLeaf(): - trie.Key = b0.Key - trie.Branch[0], trie.Branch[1] = nil, nil + tr.Key = b0.Key + tr.Branch[0], tr.Branch[1] = nil, nil } } // Add adds the key to trie, returning a new trie. // Add is immutable/non-destructive: The original trie remains unchanged. -func Add[T any](trie *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { - return AddAtDepth(0, trie, kk, data) +func Add[T any](tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { + return AddAtDepth(0, tr, kk, data) } -func AddAtDepth[T any](depth int, trie *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { +func AddAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { switch { - case trie.IsEmptyLeaf(): + case tr.IsEmptyLeaf(): return &Trie[T]{Key: kk, Data: data}, nil - case trie.IsNonEmptyLeaf(): - eq := trie.Key.Equal(kk) + case tr.IsNonEmptyLeaf(): + if tr.Key.Size() != kk.Size() { + return nil, ErrMismatchedKeyLength + } + eq := tr.Key.Equal(kk) if eq { - return trie, nil + return tr, nil } - return trieForTwo[T](depth, trie.Key, trie.Data, kk, data), nil + return trieForTwo[T](depth, tr.Key, tr.Data, kk, data), nil default: dir := kk.BitAt(depth) s := &Trie[T]{} - b, err := AddAtDepth(depth+1, trie.Branch[dir], kk, data) + b, err := AddAtDepth(depth+1, tr.Branch[dir], kk, data) if err != nil { return nil, err } s.Branch[dir] = b - s.Branch[1-dir] = trie.Branch[1-dir] + s.Branch[1-dir] = tr.Branch[1-dir] return s, nil } } @@ -149,69 +155,90 @@ func trieForTwo[T any](depth int, p key.KadKey, pdata T, q key.KadKey, qdata T) } } -func Remove[T any](trie *Trie[T], q key.KadKey) (*Trie[T], error) { - return RemoveAtDepth(0, trie, q) +// Remove is immutable/non-destructive: The original trie remains unchanged. +func Remove[T any](tr *Trie[T], q key.KadKey) (*Trie[T], error) { + return RemoveAtDepth(0, tr, q) } -func RemoveAtDepth[T any](depth int, trie *Trie[T], q key.KadKey) (*Trie[T], error) { +func RemoveAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) (*Trie[T], error) { switch { - case trie.IsEmptyLeaf(): - return trie, nil - case trie.IsNonEmptyLeaf(): - eq := trie.Key.Equal(q) + case tr.IsEmptyLeaf(): + return tr, nil + case tr.IsNonEmptyLeaf(): + if tr.Key.Size() != kk.Size() { + return nil, ErrMismatchedKeyLength + } + eq := tr.Key.Equal(kk) if !eq { - return trie, nil + return tr, nil } return &Trie[T]{}, nil default: - dir := q.BitAt(depth) - b, err := RemoveAtDepth(depth+1, trie.Branch[dir], q) + dir := kk.BitAt(depth) + b, err := RemoveAtDepth(depth+1, tr.Branch[dir], kk) if err != nil { return nil, err } afterDelete := b - if afterDelete == trie.Branch[dir] { - return trie, nil + if afterDelete == tr.Branch[dir] { + return tr, nil } copy := &Trie[T]{} copy.Branch[dir] = afterDelete - copy.Branch[1-dir] = trie.Branch[1-dir] + copy.Branch[1-dir] = tr.Branch[1-dir] copy.shrink() return copy, nil } } -func Equal[T any](p, q *Trie[T]) bool { +func Equal[T any](a, b *Trie[T]) bool { switch { - case p.IsLeaf() && q.IsLeaf(): - eq := p.Key.Equal(q.Key) + case a.IsLeaf() && b.IsLeaf(): + eq := a.Key.Equal(b.Key) if !eq { return false } return true - case !p.IsLeaf() && !q.IsLeaf(): - return Equal(p.Branch[0], q.Branch[0]) && Equal(p.Branch[1], q.Branch[1]) + case !a.IsLeaf() && !b.IsLeaf(): + return Equal(a.Branch[0], b.Branch[0]) && Equal(a.Branch[1], b.Branch[1]) } return false } -// Find looks for the key in the trie. +// Find looks for a key in the trie. +// It reports whether the key was found along with data value held with the key. +func Find[T any](tr *Trie[T], kk key.KadKey) (bool, T) { + f, _ := findFromDepth(tr, 0, kk) + if f == nil { + var v T + return false, v + } + return true, f.Data +} + +// Locate looks for the position of a key in the trie. // It reports whether the key was found along with the depth of the leaf reached along the path // of the key, regardless of whether the key was found in that leaf. -func Find[T any](trie *Trie[T], kk key.KadKey) (bool, T, int) { - return FindAtDepth(trie, 0, kk) +func Locate[T any](tr *Trie[T], kk key.KadKey) (bool, int) { + f, depth := findFromDepth(tr, 0, kk) + if f == nil { + return false, depth + } + return true, depth } -func FindAtDepth[T any](trie *Trie[T], depth int, kk key.KadKey) (bool, T, int) { +func findFromDepth[T any](tr *Trie[T], depth int, kk key.KadKey) (*Trie[T], int) { switch { - case trie.IsEmptyLeaf(): - var v T - return false, v, depth - case trie.IsNonEmptyLeaf(): - eq := trie.Key.Equal(kk) - return eq, trie.Data, depth + case tr.IsEmptyLeaf(): + return nil, depth + case tr.IsNonEmptyLeaf(): + eq := tr.Key.Equal(kk) + if !eq { + return nil, depth + } + return tr, depth default: - return FindAtDepth(trie.Branch[kk.BitAt(depth)], depth+1, kk) + return findFromDepth(tr.Branch[kk.BitAt(depth)], depth+1, kk) } } diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index a0883d1..bf6cec4 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -7,7 +7,7 @@ import ( "github.com/plprobelab/go-kademlia/key" ) -func FromKeys[T any](kks []key.KadKey) (*Trie[T], error) { +func trieFromKeys[T any](kks []key.KadKey) (*Trie[T], error) { t := New[T]() var err error for _, kk := range kks { @@ -34,7 +34,7 @@ func testSeq[T any](tr *Trie[T], t *testing.T) { if err != nil { t.Fatalf("unexpected error during add: %v", err) } - found, _, depth := Find(tr, s.key) + found, depth := Locate(tr, s.key) if !found { t.Fatalf("key not found: %v", s.key) } @@ -50,7 +50,7 @@ func testSeq[T any](tr *Trie[T], t *testing.T) { if err != nil { t.Fatalf("unexpected error during remove: %v", err) } - found, _, _ := Find(tr, s.key) + found, _ := Locate(tr, s.key) if found { t.Fatalf("key unexpectedly found: %v", s.key) } @@ -62,7 +62,7 @@ func testSeq[T any](tr *Trie[T], t *testing.T) { func TestCopy(t *testing.T) { for _, sample := range testAddSamples { - trie, err := FromKeys[any](sample.Keys) + trie, err := trieFromKeys[any](sample.Keys) if err != nil { t.Fatalf("unexpected error during from keys: %v", err) } @@ -172,26 +172,26 @@ type InvariantDiscrepancy struct { } // CheckInvariant panics of the trie does not meet its invariant. -func CheckInvariant[T any](trie *Trie[T]) *InvariantDiscrepancy { - return checkInvariant(trie, 0, nil) +func CheckInvariant[T any](tr *Trie[T]) *InvariantDiscrepancy { + return checkInvariant(tr, 0, nil) } -func checkInvariant[T any](trie *Trie[T], depth int, pathSoFar *triePath) *InvariantDiscrepancy { +func checkInvariant[T any](tr *Trie[T], depth int, pathSoFar *triePath) *InvariantDiscrepancy { switch { - case trie.IsEmptyLeaf(): + case tr.IsEmptyLeaf(): return nil - case trie.IsNonEmptyLeaf(): - if !pathSoFar.matchesKey(trie.Key) { + case tr.IsNonEmptyLeaf(): + if !pathSoFar.matchesKey(tr.Key) { return &InvariantDiscrepancy{ Reason: "key found at invalid location in trie", PathToDiscrepancy: pathSoFar.BitString(), - KeyAtDiscrepancy: trie.Key.BitString(), + KeyAtDiscrepancy: tr.Key.BitString(), } } return nil default: - if trie.IsEmpty() { - b0, b1 := trie.Branch[0], trie.Branch[1] + if !tr.HasKey() { + b0, b1 := tr.Branch[0], tr.Branch[1] if d0 := checkInvariant(b0, depth+1, pathSoFar.Push(0)); d0 != nil { return d0 } @@ -224,7 +224,7 @@ func checkInvariant[T any](trie *Trie[T], depth int, pathSoFar *triePath) *Invar return &InvariantDiscrepancy{ Reason: "intermediate node with a key", PathToDiscrepancy: pathSoFar.BitString(), - KeyAtDiscrepancy: trie.Key.BitString(), + KeyAtDiscrepancy: tr.Key.BitString(), } } } diff --git a/routing/triert/table.go b/routing/triert/table.go index 750f7cb..0aa7566 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -2,7 +2,6 @@ package triert import ( "context" - "errors" "sync" "sync/atomic" @@ -11,10 +10,6 @@ import ( "github.com/plprobelab/go-kademlia/network/address" ) -// TODO: move to key package and replace ErrInvalidKey -// ErrKeyWrongLength indicates a key has the wrong length -var ErrKeyWrongLength = errors.New("key has wrong length") - // TrieRT is a routing table backed by a Xor Trie which offers good scalablity and performance // for large networks. All exported methods are safe for concurrent use. type TrieRT struct { @@ -46,7 +41,7 @@ func (rt *TrieRT) Self() key.KadKey { func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error) { kk := node.Key() if kk.Size() != rt.self.Size() { - return false, ErrKeyWrongLength + return false, trie.ErrMismatchedKeyLength } rt.keymu.Lock() @@ -70,7 +65,7 @@ func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error // routing table func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { if kk.Size() != rt.self.Size() { - return false, ErrKeyWrongLength + return false, trie.ErrMismatchedKeyLength } rt.keymu.Lock() defer rt.keymu.Unlock() @@ -92,7 +87,7 @@ func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { // NearestPeers returns the n closest peers to a given key func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]address.NodeID, error) { if kk.Size() != rt.self.Size() { - return nil, ErrKeyWrongLength + return nil, trie.ErrMismatchedKeyLength } keys := rt.keys.Load().(*nodeTrie) @@ -138,12 +133,12 @@ func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { if kk.Size() != rt.self.Size() { - return nil, ErrKeyWrongLength + return nil, trie.ErrMismatchedKeyLength } keys := rt.keys.Load().(*nodeTrie) - found, node, _ := trie.Find(keys, kk) + found, node := trie.Find(keys, kk) if found { return node, nil @@ -171,7 +166,7 @@ func (rt *TrieRT) CplSize(cpl int) int { func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { // special cases for very small tables where keys may be placed higher in the trie due to low population if t.IsLeaf() { - if t.IsEmpty() { + if t.HasKey() { return 0, nil } keyCpl := kk.CommonPrefixLength(key.KadKey(t.Key)) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index dd05236..d4c7e76 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" "github.com/stretchr/testify/require" ) @@ -196,25 +197,25 @@ func TestInvalidKeys(t *testing.T) { t.Run("add peer", func(t *testing.T) { success, err := rt.AddPeer(ctx, incompatNode) - require.ErrorIs(t, err, ErrKeyWrongLength) + require.ErrorIs(t, err, trie.ErrMismatchedKeyLength) require.False(t, success) }) t.Run("remove key", func(t *testing.T) { success, err := rt.RemoveKey(ctx, incompatKey) - require.ErrorIs(t, err, ErrKeyWrongLength) + require.ErrorIs(t, err, trie.ErrMismatchedKeyLength) require.False(t, success) }) t.Run("find", func(t *testing.T) { nodeID, err := rt.Find(ctx, incompatKey) - require.ErrorIs(t, err, ErrKeyWrongLength) + require.ErrorIs(t, err, trie.ErrMismatchedKeyLength) require.Nil(t, nodeID) }) t.Run("nearest peers", func(t *testing.T) { nodeIDs, err := rt.NearestPeers(ctx, incompatKey, 2) - require.ErrorIs(t, err, ErrKeyWrongLength) + require.ErrorIs(t, err, trie.ErrMismatchedKeyLength) require.Nil(t, nodeIDs) }) } From bfba04d0c0a480bfec586257db575c3097f8fe44 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:11:04 +0100 Subject: [PATCH 15/32] Improve trie test coverage --- key/keyutil/keyutil.go | 53 ++++++++ key/trie/README.md | 2 + key/trie/trie.go | 107 +++++++-------- key/trie/trie_test.go | 256 ++++++++++++++++++++++++++++------- routing/triert/table_test.go | 82 ++++------- 5 files changed, 347 insertions(+), 153 deletions(-) create mode 100644 key/keyutil/keyutil.go diff --git a/key/keyutil/keyutil.go b/key/keyutil/keyutil.go new file mode 100644 index 0000000..7aacc6f --- /dev/null +++ b/key/keyutil/keyutil.go @@ -0,0 +1,53 @@ +package keyutil + +import ( + "crypto/rand" + "encoding/binary" + "strconv" + + "github.com/plprobelab/go-kademlia/key" +) + +// Random returns a KadKey of length l populated with random data. +func Random(l int) key.KadKey { + buf := make([]byte, l) + if _, err := rand.Read(buf); err != nil { + panic("RandomWithPrefix: failed to read enough entropy for key") + } + return buf +} + +// RandomWithPrefix returns a KadKey of length l having a prefix equal to the bit pattern held in s. +func RandomWithPrefix(s string, l int) key.KadKey { + kk := Random(l) + if s == "" { + return kk + } + + bits := len(s) + if bits > 64 { + panic("RandomWithPrefix: prefix too long") + } + n, err := strconv.ParseInt(s, 2, 64) + if err != nil { + panic("RandomWithPrefix: " + err.Error()) + } + prefix := uint64(n) << (64 - bits) + + size := l + if size < 8 { + size = 8 + } + + buf := make([]byte, size) + if _, err := rand.Read(buf); err != nil { + panic("RandomWithPrefix: failed to read enough entropy for key") + } + + lead := binary.BigEndian.Uint64(buf) + lead <<= bits + lead >>= bits + lead |= prefix + binary.BigEndian.PutUint64(buf, lead) + return key.KadKey(buf[:l]) +} diff --git a/key/trie/README.md b/key/trie/README.md index db342a7..914a868 100644 --- a/key/trie/README.md +++ b/key/trie/README.md @@ -1,3 +1,5 @@ # Trie This package contains an implementation of a XOR Trie. + +The trie is to be treated as immutable. Mutator functions such as Add and Remove return copies of the trie. diff --git a/key/trie/trie.go b/key/trie/trie.go index 78fa191..09805e6 100644 --- a/key/trie/trie.go +++ b/key/trie/trie.go @@ -25,34 +25,13 @@ func New[T any]() *Trie[T] { return &Trie[T]{} } -// Depth returns the maximum depth of the Trie. -func (tr *Trie[T]) Depth() int { - return tr.DepthAtDepth(0) -} - -// Depth returns the maximum depth at or beyond depth d. -func (tr *Trie[T]) DepthAtDepth(d int) int { - if tr.IsLeaf() { - return d - } else { - return max(tr.Branch[0].DepthAtDepth(d+1), tr.Branch[1].DepthAtDepth(d+1)) - } -} - -func max(x, y int) int { - if x > y { - return x - } - return y -} - // Size returns the number of keys added to the trie. func (tr *Trie[T]) Size() int { - return tr.SizeAtDepth(0) + return tr.sizeAtDepth(0) } // Size returns the number of keys added to the trie at or beyond depth d. -func (tr *Trie[T]) SizeAtDepth(d int) int { +func (tr *Trie[T]) sizeAtDepth(d int) int { if tr.IsLeaf() { if !tr.HasKey() { return 0 @@ -60,7 +39,7 @@ func (tr *Trie[T]) SizeAtDepth(d int) int { return 1 } } else { - return tr.Branch[0].SizeAtDepth(d+1) + tr.Branch[1].SizeAtDepth(d+1) + return tr.Branch[0].sizeAtDepth(d+1) + tr.Branch[1].sizeAtDepth(d+1) } } @@ -74,10 +53,12 @@ func (tr *Trie[T]) IsLeaf() bool { return tr.Branch[0] == nil && tr.Branch[1] == nil } +// IsEmptyLeaf reports whether the Trie is a leaf node without branches that also has no key. func (tr *Trie[T]) IsEmptyLeaf() bool { return !tr.HasKey() && tr.IsLeaf() } +// IsEmptyLeaf reports whether the Trie is a leaf node without branches but has a key. func (tr *Trie[T]) IsNonEmptyLeaf() bool { return tr.HasKey() && tr.IsLeaf() } @@ -107,36 +88,52 @@ func (tr *Trie[T]) shrink() { } } +func (tr *Trie[T]) firstNonEmptyLeaf() *Trie[T] { + if tr.IsLeaf() { + if tr.HasKey() { + return tr + } + return nil + } + f := tr.Branch[0].firstNonEmptyLeaf() + if f != nil { + return f + } + return tr.Branch[1].firstNonEmptyLeaf() +} + // Add adds the key to trie, returning a new trie. -// Add is immutable/non-destructive: The original trie remains unchanged. +// Add is immutable/non-destructive: the original trie remains unchanged. func Add[T any](tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { - return AddAtDepth(0, tr, kk, data) + f := tr.firstNonEmptyLeaf() + if f != nil { + if f.Key.Size() != kk.Size() { + return tr, ErrMismatchedKeyLength + } + } + return addAtDepth(0, tr, kk, data), nil } -func AddAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { +func addAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey, data T) *Trie[T] { switch { case tr.IsEmptyLeaf(): - return &Trie[T]{Key: kk, Data: data}, nil + return &Trie[T]{Key: kk, Data: data} case tr.IsNonEmptyLeaf(): if tr.Key.Size() != kk.Size() { - return nil, ErrMismatchedKeyLength + return nil } eq := tr.Key.Equal(kk) if eq { - return tr, nil + return tr } - return trieForTwo[T](depth, tr.Key, tr.Data, kk, data), nil + return trieForTwo(depth, tr.Key, tr.Data, kk, data) default: dir := kk.BitAt(depth) s := &Trie[T]{} - b, err := AddAtDepth(depth+1, tr.Branch[dir], kk, data) - if err != nil { - return nil, err - } - s.Branch[dir] = b + s.Branch[dir] = addAtDepth(depth+1, tr.Branch[dir], kk, data) s.Branch[1-dir] = tr.Branch[1-dir] - return s, nil + return s } } @@ -144,7 +141,7 @@ func trieForTwo[T any](depth int, p key.KadKey, pdata T, q key.KadKey, qdata T) pDir, qDir := p.BitAt(depth), q.BitAt(depth) if qDir == pDir { s := &Trie[T]{} - s.Branch[pDir] = trieForTwo[T](depth+1, p, pdata, q, qdata) + s.Branch[pDir] = trieForTwo(depth+1, p, pdata, q, qdata) s.Branch[1-pDir] = &Trie[T]{} return s } else { @@ -155,40 +152,44 @@ func trieForTwo[T any](depth int, p key.KadKey, pdata T, q key.KadKey, qdata T) } } -// Remove is immutable/non-destructive: The original trie remains unchanged. -func Remove[T any](tr *Trie[T], q key.KadKey) (*Trie[T], error) { - return RemoveAtDepth(0, tr, q) +// Remove removes the key from the trie. +// Remove is immutable/non-destructive: the original trie remains unchanged. +// If the key did not exist in the trie then the original trie is returned. +func Remove[T any](tr *Trie[T], kk key.KadKey) (*Trie[T], error) { + f := tr.firstNonEmptyLeaf() + if f != nil { + if f.Key.Size() != kk.Size() { + return tr, ErrMismatchedKeyLength + } + } + return removeAtDepth(0, tr, kk), nil } -func RemoveAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) (*Trie[T], error) { +func removeAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) *Trie[T] { switch { case tr.IsEmptyLeaf(): - return tr, nil + return tr case tr.IsNonEmptyLeaf(): if tr.Key.Size() != kk.Size() { - return nil, ErrMismatchedKeyLength + return nil } eq := tr.Key.Equal(kk) if !eq { - return tr, nil + return tr } - return &Trie[T]{}, nil + return &Trie[T]{} default: dir := kk.BitAt(depth) - b, err := RemoveAtDepth(depth+1, tr.Branch[dir], kk) - if err != nil { - return nil, err - } - afterDelete := b + afterDelete := removeAtDepth(depth+1, tr.Branch[dir], kk) if afterDelete == tr.Branch[dir] { - return tr, nil + return tr } copy := &Trie[T]{} copy.Branch[dir] = afterDelete copy.Branch[1-dir] = tr.Branch[1-dir] copy.shrink() - return copy, nil + return copy } } diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index bf6cec4..e114cd0 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/key/keyutil" + "github.com/stretchr/testify/require" ) func trieFromKeys[T any](kks []key.KadKey) (*Trie[T], error) { @@ -20,13 +22,14 @@ func trieFromKeys[T any](kks []key.KadKey) (*Trie[T], error) { return t, nil } -func TestInsertRemove(t *testing.T) { +func TestRepeatedAddRemove(t *testing.T) { r := New[any]() - testSeq(r, t) - testSeq(r, t) + testSeq(t, r) + testSeq(t, r) } -func testSeq[T any](tr *Trie[T], t *testing.T) { +func testSeq[T any](t *testing.T, tr *Trie[T]) { + t.Helper() var err error for _, s := range testInsertSeq { var v T @@ -61,21 +64,19 @@ func testSeq[T any](tr *Trie[T], t *testing.T) { } func TestCopy(t *testing.T) { - for _, sample := range testAddSamples { - trie, err := trieFromKeys[any](sample.Keys) - if err != nil { - t.Fatalf("unexpected error during from keys: %v", err) - } - copy := trie.Copy() - if d := CheckInvariant(copy); d != nil { - t.Fatalf("trie invariant discrepancy: %v", d) - } - if trie == copy { - t.Errorf("Expected trie copy not to be the same reference as original") - } - if !Equal(trie, copy) { - t.Errorf("Expected tries to be equal, original: %v\n, copy: %v\n", trie, copy) - } + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + copy := tr.Copy() + if d := CheckInvariant(copy); d != nil { + t.Fatalf("trie invariant discrepancy: %v", d) + } + if tr == copy { + t.Errorf("Expected trie copy not to be the same reference as original") + } + if !Equal(tr, copy) { + t.Errorf("Expected tries to be equal, original: %v\n, copy: %v\n", tr, copy) } } @@ -102,7 +103,7 @@ var testRemoveSeq = []struct { } func TestAddIsOrderIndependent(t *testing.T) { - for _, s := range append(testAddSamples, randomTestAddSamples(100)...) { + for _, s := range newKeySetList(100) { base := New[any]() for _, k := range s.Keys { base, _ = Add(base, k, nil) @@ -126,42 +127,205 @@ func TestAddIsOrderIndependent(t *testing.T) { } } -type testAddSample struct { - Keys []key.KadKey +func TestSize(t *testing.T) { + tr := New[any]() + require.Equal(t, 0, tr.Size()) + + var err error + for _, kk := range sampleKeySet.Keys { + tr, err = Add(tr, kk, nil) + require.NoError(t, err) + } + + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) +} + +func TestAddIgnoresDuplicates(t *testing.T) { + tr := New[any]() + var err error + for _, kk := range sampleKeySet.Keys { + tr, err = Add(tr, kk, nil) + require.NoError(t, err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + for _, kk := range sampleKeySet.Keys { + tr, err = Add(tr, kk, nil) + require.NoError(t, err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestAddRejectsMismatchedKeyLength(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + + trNext, err := Add(tr, keyutil.Random(5), nil) + require.ErrorIs(t, err, ErrMismatchedKeyLength) + + // trie has not been changed + require.Same(t, tr, trNext) + + if d := CheckInvariant(trNext); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestRemove(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + trNext, err := Remove(tr, sampleKeySet.Keys[0]) + require.NoError(t, err) + require.Equal(t, len(sampleKeySet.Keys)-1, trNext.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestRemoveFromEmpty(t *testing.T) { + tr := New[any]() + trNext, err := Remove(tr, sampleKeySet.Keys[0]) + require.NoError(t, err) + require.Equal(t, 0, tr.Size()) + + // trie has not been changed + require.Same(t, tr, trNext) +} + +func TestRemoveRejectsMismatchedKeyLength(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + + trNext, err := Remove(tr, keyutil.Random(5)) + require.ErrorIs(t, err, ErrMismatchedKeyLength) + + // trie has not been changed + require.Same(t, tr, trNext) + + if d := CheckInvariant(trNext); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestEqual(t *testing.T) { + a, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + b, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.True(t, Equal(a, b)) + + sampleKeySet2 := newKeySetOfLength(12, 8) + c, err := trieFromKeys[any](sampleKeySet2.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.False(t, Equal(a, c)) +} + +func TestEqualRejectsMismatchedKeyLength(t *testing.T) { + a, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + b, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.True(t, Equal(a, b)) } -var testAddSamples = []*testAddSample{ - {Keys: []key.KadKey{[]byte{1}, []byte{3}, []byte{5}, []byte{7}, []byte{11}, []byte{13}}}, - {Keys: []key.KadKey{ - []byte{11}, - []byte{22}, - []byte{23}, - []byte{25}, - []byte{27}, - []byte{28}, - []byte{31}, - []byte{32}, - []byte{33}, - }}, +func TestFindNoData(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + + for _, kk := range sampleKeySet.Keys { + found, _ := Find(tr, kk) + require.True(t, found) + } } -func randomTestAddSamples(count int) []*testAddSample { - s := make([]*testAddSample, count) +func TestFindNotFound(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys[1:]) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + + found, _ := Find(tr, sampleKeySet.Keys[0]) + require.False(t, found) +} + +func TestFindMismatchedKeyLength(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + + found, _ := Find(tr, keyutil.Random(5)) + require.False(t, found) +} + +func TestFindWithData(t *testing.T) { + tr := New[int]() + + var err error + for i, kk := range sampleKeySet.Keys { + tr, err = Add(tr, kk, i) + require.NoError(t, err) + } + + for i, kk := range sampleKeySet.Keys { + found, v := Find(tr, kk) + require.True(t, found) + require.Equal(t, i, v) + } +} + +type keySet struct { + Keys []key.KadKey +} + +var sampleKeySet = newKeySetOfLength(12, 8) + +func newKeySetList(n int) []*keySet { + s := make([]*keySet, n) for i := range s { - s[i] = randomTestAddSample(31, 2) + s[i] = newKeySetOfLength(31, 4) } return s } -func randomTestAddSample(setSize, keySizeByte int) *testAddSample { - keySet := make([]key.KadKey, setSize) - for i := range keySet { - k := make([]byte, keySizeByte) - rand.Read(k) - keySet[i] = key.KadKey(k) +func newKeySetOfLength(n int, l int) *keySet { + set := make([]key.KadKey, 0, n) + seen := make(map[string]bool) + for len(set) < n { + kk := keyutil.Random(l) + if seen[kk.String()] { + continue + } + seen[kk.String()] = true + set = append(set, kk) } - return &testAddSample{ - Keys: keySet, + return &keySet{ + Keys: set, } } diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index d4c7e76..013c8db 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -2,12 +2,10 @@ package triert import ( "context" - "crypto/rand" - "encoding/binary" - "strconv" "testing" "github.com/plprobelab/go-kademlia/key" + "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" "github.com/stretchr/testify/require" @@ -16,17 +14,17 @@ import ( var ( key0 = key.KadKey(make([]byte, 32)) // 000000...000 - key1 = keyWithPrefix("010000", 32) - key2 = keyWithPrefix("100000", 32) - key3 = keyWithPrefix("110000", 32) - key4 = keyWithPrefix("111000", 32) - key5 = keyWithPrefix("011000", 32) - key6 = keyWithPrefix("011100", 32) - key7 = keyWithPrefix("000110", 32) - key8 = keyWithPrefix("000101", 32) - key9 = keyWithPrefix("000100", 32) - key10 = keyWithPrefix("001000", 32) - key11 = keyWithPrefix("001100", 32) + key1 = keyutil.RandomWithPrefix("010000", 32) + key2 = keyutil.RandomWithPrefix("100000", 32) + key3 = keyutil.RandomWithPrefix("110000", 32) + key4 = keyutil.RandomWithPrefix("111000", 32) + key5 = keyutil.RandomWithPrefix("011000", 32) + key6 = keyutil.RandomWithPrefix("011100", 32) + key7 = keyutil.RandomWithPrefix("000110", 32) + key8 = keyutil.RandomWithPrefix("000101", 32) + key9 = keyutil.RandomWithPrefix("000100", 32) + key10 = keyutil.RandomWithPrefix("001000", 32) + key11 = keyutil.RandomWithPrefix("001100", 32) node1 = NewNode("QmPeer1", key1) node2 = NewNode("QmPeer2", key2) @@ -234,10 +232,10 @@ func TestCplSize(t *testing.T) { ctx := context.Background() rt := New(key0) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) require.Equal(t, 2, rt.Size()) @@ -251,10 +249,10 @@ func TestCplSize(t *testing.T) { ctx := context.Background() rt := New(key0) - success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyWithPrefix("001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) @@ -269,16 +267,16 @@ func TestCplSize(t *testing.T) { ctx := context.Background() rt := New(key0) - success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyWithPrefix("0001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) @@ -293,30 +291,30 @@ func TestCplSize(t *testing.T) { ctx := context.Background() rt := New(key0) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2a", keyWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2a", keyutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3a", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3a", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) @@ -327,30 +325,6 @@ func TestCplSize(t *testing.T) { }) } -func keyWithPrefix(s string, length int) key.KadKey { - bits := len(s) - if bits > 64 { - panic("keyWithPrefix: prefix too long") - } - n, err := strconv.ParseInt(s, 2, 64) - if err != nil { - panic("keyWithPrefix: " + err.Error()) - } - prefix := uint64(n) << (64 - bits) - - buf := make([]byte, length) - if _, err := rand.Read(buf); err != nil { - panic("keyWithPrefix: failed to read enough entropy for key") - } - - lead := binary.BigEndian.Uint64(buf) - lead <<= bits - lead >>= bits - lead |= prefix - binary.BigEndian.PutUint64(buf, lead) - return key.KadKey(buf) -} - var _ address.NodeID = (*node)(nil) type node struct { From 29e5c75c19bb0901d205407db8f8835e4739b10b Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:14:25 +0100 Subject: [PATCH 16/32] go mod tidy --- go.mod | 5 -- go.sum | 153 --------------------------------------------------------- 2 files changed, 158 deletions(-) diff --git a/go.mod b/go.mod index 2b21cc3..2265d69 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/benbjohnson/clock v1.3.5 github.com/ipfs/go-cid v0.4.1 github.com/libp2p/go-libp2p v0.28.1 - github.com/libp2p/go-libp2p-xor v0.1.0 github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.10.0 github.com/multiformats/go-multibase v0.2.0 @@ -43,8 +42,6 @@ require ( github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/huin/goupnp v1.2.0 // indirect - github.com/ipfs/boxo v0.10.2 // indirect - github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect @@ -56,7 +53,6 @@ require ( 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.6.3 // 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 @@ -77,7 +73,6 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1fadcf1..0b056fa 100644 --- a/go.sum +++ b/go.sum @@ -7,11 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -20,15 +17,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 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/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -37,19 +25,13 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -58,8 +40,6 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -75,7 +55,6 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -89,13 +68,10 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/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/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= @@ -106,10 +82,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.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/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.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= @@ -121,8 +95,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -130,57 +102,28 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/ipfs/boxo v0.10.2 h1:kspw9HmMyKzLQxpKk417sF69i6iuf50AXtRjFqCYyL4= -github.com/ipfs/boxo v0.10.2/go.mod h1:1qgKq45mPRCxf4ZPoJV2lnXxyxucigILMJOrQrVivv8= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 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.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -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= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 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/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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -191,59 +134,37 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= 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.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= 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.1 h1:YurK+ZAI6cKfASLJBVFkpVBdl3wGhFi6fusOt725ii8= github.com/libp2p/go-libp2p v0.28.1/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-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio= -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-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= -github.com/libp2p/go-libp2p-xor v0.1.0 h1:hhQwT4uGrBcuAkUGXADuPltalOdpf9aag9kaYNT2tLA= -github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= 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-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-reuseport v0.3.0 h1:iiZslO5byUYZEg9iCwJGf5h+sf1Agmqx2V2FDjPyvUw= github.com/libp2p/go-reuseport v0.3.0/go.mod h1:laea40AimhtfEqysZ71UpYj4S+R9VpH8PgqLo7L+SwI= github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -255,26 +176,18 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKo github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.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.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= 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.0 h1:onErs0qLf3P2oRqrYk1fAMcfrWaJb58pYY43SkEF78w= @@ -283,41 +196,28 @@ github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2 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-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -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.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= 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.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/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 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/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.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= @@ -347,7 +247,6 @@ github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2Ep github.com/quic-go/webtransport-go v0.5.3/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= 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= @@ -375,23 +274,12 @@ 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= 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.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -400,23 +288,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 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= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 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/exporters/jaeger v1.16.0 h1:YhxxmXZ011C0aDZKoNw+juVWAmEfv/0W2XBOv9aHTaA= @@ -427,7 +306,6 @@ go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiM go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= go.opentelemetry.io/otel/trace v1.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= @@ -438,25 +316,17 @@ go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.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= 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= -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-20190211182817-74369b46fc67/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= @@ -470,10 +340,8 @@ golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N0 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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -487,7 +355,6 @@ golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/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= @@ -516,17 +383,11 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-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-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -543,24 +404,18 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-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= @@ -585,12 +440,10 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA 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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 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/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= @@ -599,12 +452,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= -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= @@ -616,7 +464,6 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= From ba305185f9a787f52c8b1ea759b58e3998485108 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Fri, 7 Jul 2023 12:02:41 +0100 Subject: [PATCH 17/32] Add BenchmarkBuildTable --- routing/triert/table_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 013c8db..0d9fb24 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -8,6 +8,7 @@ import ( "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" + "github.com/plprobelab/go-kademlia/network/address/kadid" "github.com/stretchr/testify/require" ) @@ -325,6 +326,29 @@ func TestCplSize(t *testing.T) { }) } +func BenchmarkBuildTable(b *testing.B) { + b.Run("1000", makeBenchmarkBuildTable(1000)) + b.Run("10000", makeBenchmarkBuildTable(10000)) + b.Run("100000", makeBenchmarkBuildTable(100000)) +} + +func makeBenchmarkBuildTable(n int) func(b *testing.B) { + return func(b *testing.B) { + nodes := make([]address.NodeID, n) + for i := 0; i < n; i++ { + nodes[i] = kadid.NewKadID(keyutil.Random(32)) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + rt := New(key0) + for _, node := range nodes { + rt.AddPeer(context.Background(), node) + } + } + } +} + var _ address.NodeID = (*node)(nil) type node struct { From ff096610a0ac4894c1409a4efd5c32d6a6238f84 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Mon, 10 Jul 2023 10:22:49 +0100 Subject: [PATCH 18/32] Add mutable Add/Remove to trie --- key/key.go | 10 ++- key/trie/trie.go | 159 +++++++++++++++++++++++++++++----------- key/trie/trie_test.go | 113 +++++++++++++++++++++++++++- routing/triert/table.go | 21 +++--- 4 files changed, 246 insertions(+), 57 deletions(-) diff --git a/key/key.go b/key/key.go index 3e41188..347dfe8 100644 --- a/key/key.go +++ b/key/key.go @@ -87,8 +87,14 @@ func (a KadKey) Equal(b KadKey) bool { return a.Compare(b) == 0 } -func (k KadKey) BitAt(offset int) int { - if k[offset/8]&(byte(1)<<(7-offset%8)) == 0 { +// BitLen returns the length of the key in bits +func (k KadKey) BitLen() int { + return len(k) * 8 +} + +// BitAt returns the value of the i'th bit of the key from most significant to least. It is equivalent to (key>>(bitlen-i-1))&1. +func (k KadKey) BitAt(i int) int { + if k[i/8]&(byte(1)<<(7-i%8)) == 0 { return 0 } else { return 1 diff --git a/key/trie/trie.go b/key/trie/trie.go index 09805e6..6f15ead 100644 --- a/key/trie/trie.go +++ b/key/trie/trie.go @@ -16,15 +16,27 @@ var ErrMismatchedKeyLength = errors.New("key length does not match existing keys // (2) If branches are non-nil, key must be nil. // (3) If both branches are leaves, then they are both non-empty (have keys). type Trie[T any] struct { - Branch [2]*Trie[T] - Key key.KadKey - Data T + branch [2]*Trie[T] + key key.KadKey + data T } func New[T any]() *Trie[T] { return &Trie[T]{} } +func (tr *Trie[T]) Key() key.KadKey { + return tr.key +} + +func (tr *Trie[T]) Data() T { + return tr.data +} + +func (tr *Trie[T]) Branch(dir int) *Trie[T] { + return tr.branch[dir] +} + // Size returns the number of keys added to the trie. func (tr *Trie[T]) Size() int { return tr.sizeAtDepth(0) @@ -39,18 +51,18 @@ func (tr *Trie[T]) sizeAtDepth(d int) int { return 1 } } else { - return tr.Branch[0].sizeAtDepth(d+1) + tr.Branch[1].sizeAtDepth(d+1) + return tr.branch[0].sizeAtDepth(d+1) + tr.branch[1].sizeAtDepth(d+1) } } // HasKey reports whether the Trie node holds a key. func (tr *Trie[T]) HasKey() bool { - return tr.Key != nil + return tr.key != nil } // IsLeaf reports whether the Trie is a leaf node. A leaf node has no child branches but may hold a key and data. func (tr *Trie[T]) IsLeaf() bool { - return tr.Branch[0] == nil && tr.Branch[1] == nil + return tr.branch[0] == nil && tr.branch[1] == nil } // IsEmptyLeaf reports whether the Trie is a leaf node without branches that also has no key. @@ -65,26 +77,26 @@ func (tr *Trie[T]) IsNonEmptyLeaf() bool { func (tr *Trie[T]) Copy() *Trie[T] { if tr.IsLeaf() { - return &Trie[T]{Key: tr.Key, Data: tr.Data} + return &Trie[T]{key: tr.key, data: tr.data} } - return &Trie[T]{Branch: [2]*Trie[T]{ - tr.Branch[0].Copy(), - tr.Branch[1].Copy(), + return &Trie[T]{branch: [2]*Trie[T]{ + tr.branch[0].Copy(), + tr.branch[1].Copy(), }} } func (tr *Trie[T]) shrink() { - b0, b1 := tr.Branch[0], tr.Branch[1] + b0, b1 := tr.branch[0], tr.branch[1] switch { case b0.IsEmptyLeaf() && b1.IsEmptyLeaf(): - tr.Branch[0], tr.Branch[1] = nil, nil + tr.branch[0], tr.branch[1] = nil, nil case b0.IsEmptyLeaf() && b1.IsNonEmptyLeaf(): - tr.Key = b1.Key - tr.Branch[0], tr.Branch[1] = nil, nil + tr.key = b1.key + tr.branch[0], tr.branch[1] = nil, nil case b0.IsNonEmptyLeaf() && b1.IsEmptyLeaf(): - tr.Key = b0.Key - tr.Branch[0], tr.Branch[1] = nil, nil + tr.key = b0.key + tr.branch[0], tr.branch[1] = nil, nil } } @@ -95,11 +107,45 @@ func (tr *Trie[T]) firstNonEmptyLeaf() *Trie[T] { } return nil } - f := tr.Branch[0].firstNonEmptyLeaf() + f := tr.branch[0].firstNonEmptyLeaf() if f != nil { return f } - return tr.Branch[1].firstNonEmptyLeaf() + return tr.branch[1].firstNonEmptyLeaf() +} + +// Add attemptes to add a key to the trie, mutating the trie. +// Returns true if the key was added, false otherwise. +func (tr *Trie[T]) Add(kk key.KadKey, data T) (bool, error) { + f := tr.firstNonEmptyLeaf() + if f != nil { + if f.key.Size() != kk.Size() { + return false, ErrMismatchedKeyLength + } + } + return tr.addAtDepth(0, kk, data), nil +} + +func (tr *Trie[T]) addAtDepth(depth int, kk key.KadKey, data T) bool { + switch { + case tr.IsEmptyLeaf(): + tr.key = kk + tr.data = data + return true + case tr.IsNonEmptyLeaf(): + if tr.key.Equal(kk) { + return false + } else { + p := tr.key + tr.key = nil + // both branches are nil + tr.branch[0], tr.branch[1] = &Trie[T]{}, &Trie[T]{} + tr.branch[p.BitAt(depth)].key = p + return tr.branch[kk.BitAt(depth)].addAtDepth(depth+1, kk, data) + } + default: + return tr.branch[kk.BitAt(depth)].addAtDepth(depth+1, kk, data) + } } // Add adds the key to trie, returning a new trie. @@ -107,7 +153,7 @@ func (tr *Trie[T]) firstNonEmptyLeaf() *Trie[T] { func Add[T any](tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { f := tr.firstNonEmptyLeaf() if f != nil { - if f.Key.Size() != kk.Size() { + if f.key.Size() != kk.Size() { return tr, ErrMismatchedKeyLength } } @@ -117,22 +163,22 @@ func Add[T any](tr *Trie[T], kk key.KadKey, data T) (*Trie[T], error) { func addAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey, data T) *Trie[T] { switch { case tr.IsEmptyLeaf(): - return &Trie[T]{Key: kk, Data: data} + return &Trie[T]{key: kk, data: data} case tr.IsNonEmptyLeaf(): - if tr.Key.Size() != kk.Size() { + if tr.key.Size() != kk.Size() { return nil } - eq := tr.Key.Equal(kk) + eq := tr.key.Equal(kk) if eq { return tr } - return trieForTwo(depth, tr.Key, tr.Data, kk, data) + return trieForTwo(depth, tr.key, tr.data, kk, data) default: dir := kk.BitAt(depth) s := &Trie[T]{} - s.Branch[dir] = addAtDepth(depth+1, tr.Branch[dir], kk, data) - s.Branch[1-dir] = tr.Branch[1-dir] + s.branch[dir] = addAtDepth(depth+1, tr.branch[dir], kk, data) + s.branch[1-dir] = tr.branch[1-dir] return s } } @@ -141,24 +187,55 @@ func trieForTwo[T any](depth int, p key.KadKey, pdata T, q key.KadKey, qdata T) pDir, qDir := p.BitAt(depth), q.BitAt(depth) if qDir == pDir { s := &Trie[T]{} - s.Branch[pDir] = trieForTwo(depth+1, p, pdata, q, qdata) - s.Branch[1-pDir] = &Trie[T]{} + s.branch[pDir] = trieForTwo(depth+1, p, pdata, q, qdata) + s.branch[1-pDir] = &Trie[T]{} return s } else { s := &Trie[T]{} - s.Branch[pDir] = &Trie[T]{Key: p, Data: pdata} - s.Branch[qDir] = &Trie[T]{Key: q, Data: qdata} + s.branch[pDir] = &Trie[T]{key: p, data: pdata} + s.branch[qDir] = &Trie[T]{key: q, data: qdata} return s } } +// Remove attempts to remove a key from the trie, mutating the trie. +// Returns true if the key was removed, false otherwise. +func (tr *Trie[T]) Remove(kk key.KadKey) (bool, error) { + f := tr.firstNonEmptyLeaf() + if f != nil { + if f.key.Size() != kk.Size() { + return false, ErrMismatchedKeyLength + } + } + return tr.removeAtDepth(0, kk), nil +} + +func (tr *Trie[T]) removeAtDepth(depth int, kk key.KadKey) bool { + switch { + case tr.IsEmptyLeaf(): + return false + case tr.IsNonEmptyLeaf(): + tr.key = nil + var v T + tr.data = v + return true + default: + if tr.branch[kk.BitAt(depth)].removeAtDepth(depth+1, kk) { + tr.shrink() + return true + } else { + return false + } + } +} + // Remove removes the key from the trie. // Remove is immutable/non-destructive: the original trie remains unchanged. // If the key did not exist in the trie then the original trie is returned. func Remove[T any](tr *Trie[T], kk key.KadKey) (*Trie[T], error) { f := tr.firstNonEmptyLeaf() if f != nil { - if f.Key.Size() != kk.Size() { + if f.key.Size() != kk.Size() { return tr, ErrMismatchedKeyLength } } @@ -170,10 +247,10 @@ func removeAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) *Trie[T] { case tr.IsEmptyLeaf(): return tr case tr.IsNonEmptyLeaf(): - if tr.Key.Size() != kk.Size() { + if tr.key.Size() != kk.Size() { return nil } - eq := tr.Key.Equal(kk) + eq := tr.key.Equal(kk) if !eq { return tr } @@ -181,13 +258,13 @@ func removeAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) *Trie[T] { default: dir := kk.BitAt(depth) - afterDelete := removeAtDepth(depth+1, tr.Branch[dir], kk) - if afterDelete == tr.Branch[dir] { + afterDelete := removeAtDepth(depth+1, tr.branch[dir], kk) + if afterDelete == tr.branch[dir] { return tr } copy := &Trie[T]{} - copy.Branch[dir] = afterDelete - copy.Branch[1-dir] = tr.Branch[1-dir] + copy.branch[dir] = afterDelete + copy.branch[1-dir] = tr.branch[1-dir] copy.shrink() return copy } @@ -196,13 +273,13 @@ func removeAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) *Trie[T] { func Equal[T any](a, b *Trie[T]) bool { switch { case a.IsLeaf() && b.IsLeaf(): - eq := a.Key.Equal(b.Key) + eq := a.key.Equal(b.key) if !eq { return false } return true case !a.IsLeaf() && !b.IsLeaf(): - return Equal(a.Branch[0], b.Branch[0]) && Equal(a.Branch[1], b.Branch[1]) + return Equal(a.branch[0], b.branch[0]) && Equal(a.branch[1], b.branch[1]) } return false } @@ -215,7 +292,7 @@ func Find[T any](tr *Trie[T], kk key.KadKey) (bool, T) { var v T return false, v } - return true, f.Data + return true, f.data } // Locate looks for the position of a key in the trie. @@ -234,12 +311,12 @@ func findFromDepth[T any](tr *Trie[T], depth int, kk key.KadKey) (*Trie[T], int) case tr.IsEmptyLeaf(): return nil, depth case tr.IsNonEmptyLeaf(): - eq := tr.Key.Equal(kk) + eq := tr.key.Equal(kk) if !eq { return nil, depth } return tr, depth default: - return findFromDepth(tr.Branch[kk.BitAt(depth)], depth+1, kk) + return findFromDepth(tr.branch[kk.BitAt(depth)], depth+1, kk) } } diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index e114cd0..19174ee 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -103,6 +103,31 @@ var testRemoveSeq = []struct { } func TestAddIsOrderIndependent(t *testing.T) { + for _, s := range newKeySetList(100) { + base := New[any]() + for _, k := range s.Keys { + base.Add(k, nil) + } + if d := CheckInvariant(base); d != nil { + t.Fatalf("base trie invariant discrepancy: %v", d) + } + for j := 0; j < 100; j++ { + perm := rand.Perm(len(s.Keys)) + reordered := New[any]() + for i := range s.Keys { + reordered.Add(s.Keys[perm[i]], nil) + } + if d := CheckInvariant(reordered); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } + if !Equal(base, reordered) { + t.Errorf("trie %v differs from trie %v", base, reordered) + } + } + } +} + +func TestImmutableAddIsOrderIndependent(t *testing.T) { for _, s := range newKeySetList(100) { base := New[any]() for _, k := range s.Keys { @@ -141,6 +166,27 @@ func TestSize(t *testing.T) { } func TestAddIgnoresDuplicates(t *testing.T) { + tr := New[any]() + for _, kk := range sampleKeySet.Keys { + added, err := tr.Add(kk, nil) + require.NoError(t, err) + require.True(t, added) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + for _, kk := range sampleKeySet.Keys { + added, err := tr.Add(kk, nil) + require.NoError(t, err) + require.False(t, added) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableAddIgnoresDuplicates(t *testing.T) { tr := New[any]() var err error for _, kk := range sampleKeySet.Keys { @@ -166,6 +212,21 @@ func TestAddRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } + added, err := tr.Add(keyutil.Random(5), nil) + require.ErrorIs(t, err, ErrMismatchedKeyLength) + require.False(t, added) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableAddRejectsMismatchedKeyLength(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + trNext, err := Add(tr, keyutil.Random(5), nil) require.ErrorIs(t, err, ErrMismatchedKeyLength) @@ -184,6 +245,23 @@ func TestRemove(t *testing.T) { } require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + removed, err := tr.Remove(sampleKeySet.Keys[0]) + require.NoError(t, err) + require.True(t, removed) + require.Equal(t, len(sampleKeySet.Keys)-1, tr.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableRemove(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + trNext, err := Remove(tr, sampleKeySet.Keys[0]) require.NoError(t, err) require.Equal(t, len(sampleKeySet.Keys)-1, trNext.Size()) @@ -194,6 +272,18 @@ func TestRemove(t *testing.T) { } func TestRemoveFromEmpty(t *testing.T) { + tr := New[any]() + removed, err := tr.Remove(sampleKeySet.Keys[0]) + require.NoError(t, err) + require.False(t, removed) + require.Equal(t, 0, tr.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableRemoveFromEmpty(t *testing.T) { tr := New[any]() trNext, err := Remove(tr, sampleKeySet.Keys[0]) require.NoError(t, err) @@ -209,6 +299,21 @@ func TestRemoveRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } + removed, err := tr.Remove(keyutil.Random(5)) + require.ErrorIs(t, err, ErrMismatchedKeyLength) + require.False(t, removed) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableRemoveRejectsMismatchedKeyLength(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + trNext, err := Remove(tr, keyutil.Random(5)) require.ErrorIs(t, err, ErrMismatchedKeyLength) @@ -345,17 +450,17 @@ func checkInvariant[T any](tr *Trie[T], depth int, pathSoFar *triePath) *Invaria case tr.IsEmptyLeaf(): return nil case tr.IsNonEmptyLeaf(): - if !pathSoFar.matchesKey(tr.Key) { + if !pathSoFar.matchesKey(tr.key) { return &InvariantDiscrepancy{ Reason: "key found at invalid location in trie", PathToDiscrepancy: pathSoFar.BitString(), - KeyAtDiscrepancy: tr.Key.BitString(), + KeyAtDiscrepancy: tr.key.BitString(), } } return nil default: if !tr.HasKey() { - b0, b1 := tr.Branch[0], tr.Branch[1] + b0, b1 := tr.branch[0], tr.branch[1] if d0 := checkInvariant(b0, depth+1, pathSoFar.Push(0)); d0 != nil { return d0 } @@ -388,7 +493,7 @@ func checkInvariant[T any](tr *Trie[T], depth int, pathSoFar *triePath) *Invaria return &InvariantDiscrepancy{ Reason: "intermediate node with a key", PathToDiscrepancy: pathSoFar.BitString(), - KeyAtDiscrepancy: tr.Key.BitString(), + KeyAtDiscrepancy: tr.key.BitString(), } } } diff --git a/routing/triert/table.go b/routing/triert/table.go index 0aa7566..733e413 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -110,12 +110,13 @@ type entry struct { } func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { - if t.Key != nil { - // We've found a leaf - return []entry{ - {Key: t.Key, Data: t.Data}, + if t.IsLeaf() { + if t.HasKey() { + // We've found a leaf + return []entry{ + {Key: t.Key(), Data: t.Data()}, + } } - } else if t.Branch[0] == nil && t.Branch[1] == nil { // We've found an empty node? return nil } @@ -123,12 +124,12 @@ func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { // Find the closest direction. dir := kk.BitAt(depth) // Add peers from the closest direction first - found := closestAtDepth(kk, t.Branch[dir], depth+1, n) + found := closestAtDepth(kk, t.Branch(dir), depth+1, n) if len(found) == n { return found } // Didn't find enough peers in the closest direction, try the other direction. - return append(found, closestAtDepth(kk, t.Branch[1-dir], depth+1, n-len(found))...) + return append(found, closestAtDepth(kk, t.Branch(1-dir), depth+1, n-len(found))...) } func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { @@ -169,7 +170,7 @@ func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { if t.HasKey() { return 0, nil } - keyCpl := kk.CommonPrefixLength(key.KadKey(t.Key)) + keyCpl := kk.CommonPrefixLength(key.KadKey(t.Key())) if keyCpl == cpl { return 1, nil } @@ -178,8 +179,8 @@ func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { if depth == cpl { // return the number of entries that do not share the next bit with kk - return t.Branch[1-kk.BitAt(depth)].Size(), nil + return t.Branch(1 - kk.BitAt(depth)).Size(), nil } - return countCpl(t.Branch[kk.BitAt(depth)], kk, cpl, depth+1) + return countCpl(t.Branch(kk.BitAt(depth)), kk, cpl, depth+1) } From f7ef0cac04490a75de10eb73f3989a07e0384d77 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:08:28 +0100 Subject: [PATCH 19/32] Add benchmarks for key/trie --- key/keyutil/keyutil.go | 12 +- key/trie/trie_test.go | 247 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 7 deletions(-) diff --git a/key/keyutil/keyutil.go b/key/keyutil/keyutil.go index 7aacc6f..4fbeee5 100644 --- a/key/keyutil/keyutil.go +++ b/key/keyutil/keyutil.go @@ -1,19 +1,19 @@ package keyutil import ( - "crypto/rand" "encoding/binary" + "math/rand" "strconv" "github.com/plprobelab/go-kademlia/key" ) +var rng = rand.New(rand.NewSource(299792458)) + // Random returns a KadKey of length l populated with random data. func Random(l int) key.KadKey { buf := make([]byte, l) - if _, err := rand.Read(buf); err != nil { - panic("RandomWithPrefix: failed to read enough entropy for key") - } + rng.Read(buf) return buf } @@ -40,9 +40,7 @@ func RandomWithPrefix(s string, l int) key.KadKey { } buf := make([]byte, size) - if _, err := rand.Read(buf); err != nil { - panic("RandomWithPrefix: failed to read enough entropy for key") - } + rng.Read(buf) lead := binary.BigEndian.Uint64(buf) lead <<= bits diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 19174ee..8e3e20b 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -404,6 +404,253 @@ func TestFindWithData(t *testing.T) { } } +func BenchmarkBuildTrieMutable(b *testing.B) { + b.Run("1000", benchmarkBuildTrieMutable(1000)) + b.Run("10000", benchmarkBuildTrieMutable(10000)) + b.Run("100000", benchmarkBuildTrieMutable(100000)) +} + +func BenchmarkBuildTrieImmutable(b *testing.B) { + b.Run("1000", benchmarkBuildTrieImmutable(1000)) + b.Run("10000", benchmarkBuildTrieImmutable(10000)) + b.Run("100000", benchmarkBuildTrieImmutable(100000)) +} + +func BenchmarkAddMutable(b *testing.B) { + b.Run("1000", benchmarkAddMutable(1000)) + b.Run("10000", benchmarkAddMutable(10000)) + b.Run("100000", benchmarkAddMutable(100000)) +} + +func BenchmarkAddImmutable(b *testing.B) { + b.Run("1000", benchmarkAddImmutable(1000)) + b.Run("10000", benchmarkAddImmutable(10000)) + b.Run("100000", benchmarkAddImmutable(100000)) +} + +func BenchmarkRemoveMutable(b *testing.B) { + b.Run("1000", benchmarkRemoveMutable(1000)) + b.Run("10000", benchmarkRemoveMutable(10000)) + b.Run("100000", benchmarkRemoveMutable(100000)) +} + +func BenchmarkRemoveImmutable(b *testing.B) { + b.Run("1000", benchmarkRemoveImmutable(1000)) + b.Run("10000", benchmarkRemoveImmutable(10000)) + b.Run("100000", benchmarkRemoveImmutable(100000)) +} + +func BenchmarkFindPositive(b *testing.B) { + b.Run("1000", benchmarkFindPositive(1000)) + b.Run("10000", benchmarkFindPositive(10000)) + b.Run("100000", benchmarkFindPositive(100000)) +} + +func BenchmarkFindNegative(b *testing.B) { + b.Run("1000", benchmarkFindNegative(1000)) + b.Run("10000", benchmarkFindNegative(10000)) + b.Run("100000", benchmarkFindNegative(100000)) +} + +func benchmarkBuildTrieMutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + tr := New[any]() + for _, kk := range keys { + tr.Add(kk, nil) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(n), "ns/key") + } +} + +func benchmarkBuildTrieImmutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + tr := New[any]() + for _, kk := range keys { + tr, _ = Add(tr, kk, nil) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(n), "ns/key") + } +} + +func benchmarkAddMutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + tr := New[any]() + for _, kk := range keys { + tr, _ = Add(tr, kk, nil) + } + + // number of additions has to be large enough so that benchmarking takes + // more time than cloning the trie + // see https://github.com/golang/go/issues/27217 + additions := make([]key.KadKey, n/4) + for i := range additions { + additions[i] = keyutil.Random(32) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + trclone := tr.Copy() + b.StartTimer() + for _, kk := range additions { + trclone.Add(kk, nil) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(additions)), "ns/key") + } +} + +func benchmarkAddImmutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + trBase := New[any]() + for _, kk := range keys { + trBase, _ = Add(trBase, kk, nil) + } + + additions := make([]key.KadKey, n/4) + for i := range additions { + additions[i] = keyutil.Random(32) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + tr := trBase + for _, kk := range additions { + tr, _ = Add(tr, kk, nil) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(additions)), "ns/key") + } +} + +func benchmarkRemoveMutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + tr := New[any]() + for _, kk := range keys { + tr, _ = Add(tr, kk, nil) + } + + // number of removals has to be large enough so that benchmarking takes + // more time than cloning the trie + // see https://github.com/golang/go/issues/27217 + removals := make([]key.KadKey, n/4) + for i := range removals { + removals[i] = keys[i*4] // every 4th key + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + b.StopTimer() + trclone := tr.Copy() + b.StartTimer() + for _, kk := range removals { + trclone.Remove(kk) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(removals)), "ns/key") + } +} + +func benchmarkRemoveImmutable(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + trBase := New[any]() + for _, kk := range keys { + trBase, _ = Add(trBase, kk, nil) + } + + removals := make([]key.KadKey, n/4) + for i := range removals { + removals[i] = keys[i*4] // every 4th key + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + tr := trBase + for _, kk := range removals { + tr, _ = Remove(tr, kk) + } + } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(removals)), "ns/key") + } +} + +func benchmarkFindPositive(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + tr := New[any]() + for _, kk := range keys { + tr, _ = Add(tr, kk, nil) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Find(tr, keys[i%len(keys)]) + } + } +} + +func benchmarkFindNegative(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + tr := New[any]() + for _, kk := range keys { + tr, _ = Add(tr, kk, nil) + } + unknown := make([]key.KadKey, n) + for i := 0; i < n; i++ { + kk := keyutil.Random(32) + if found, _ := Find(tr, kk); found { + continue + } + unknown[i] = kk + } + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + Find(tr, unknown[i%len(unknown)]) + } + } +} + type keySet struct { Keys []key.KadKey } From cc37031a2c1b47eb0934e1cfde4e1dbfb007a697 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:23:28 +0100 Subject: [PATCH 20/32] Add benchmarks for routing/triert --- routing/triert/table_test.go | 91 ++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 0d9fb24..ad79b6f 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -327,12 +327,30 @@ func TestCplSize(t *testing.T) { } func BenchmarkBuildTable(b *testing.B) { - b.Run("1000", makeBenchmarkBuildTable(1000)) - b.Run("10000", makeBenchmarkBuildTable(10000)) - b.Run("100000", makeBenchmarkBuildTable(100000)) + b.Run("1000", benchmarkBuildTable(1000)) + b.Run("10000", benchmarkBuildTable(10000)) + b.Run("100000", benchmarkBuildTable(100000)) } -func makeBenchmarkBuildTable(n int) func(b *testing.B) { +func BenchmarkFindPositive(b *testing.B) { + b.Run("1000", benchmarkFindPositive(1000)) + b.Run("10000", benchmarkFindPositive(10000)) + b.Run("100000", benchmarkFindPositive(100000)) +} + +func BenchmarkFindNegative(b *testing.B) { + b.Run("1000", benchmarkFindNegative(1000)) + b.Run("10000", benchmarkFindNegative(10000)) + b.Run("100000", benchmarkFindNegative(100000)) +} + +func BenchmarkNearestPeers(b *testing.B) { + b.Run("1000", benchmarkNearestPeers(1000)) + b.Run("10000", benchmarkNearestPeers(10000)) + b.Run("100000", benchmarkNearestPeers(100000)) +} + +func benchmarkBuildTable(n int) func(b *testing.B) { return func(b *testing.B) { nodes := make([]address.NodeID, n) for i := 0; i < n; i++ { @@ -346,6 +364,71 @@ func makeBenchmarkBuildTable(n int) func(b *testing.B) { rt.AddPeer(context.Background(), node) } } + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(nodes)), "ns/node") + } +} + +func benchmarkFindPositive(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + rt := New(key0) + for _, kk := range keys { + rt.AddPeer(context.Background(), kadid.NewKadID(kk)) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + rt.Find(context.Background(), keys[i%len(keys)]) + } + } +} + +func benchmarkFindNegative(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + rt := New(key0) + for _, kk := range keys { + rt.AddPeer(context.Background(), kadid.NewKadID(kk)) + } + + unknown := make([]key.KadKey, n) + for i := 0; i < n; i++ { + kk := keyutil.Random(32) + if found, _ := rt.Find(context.Background(), kk); found != nil { + continue + } + unknown[i] = kk + } + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + rt.Find(context.Background(), unknown[i%len(unknown)]) + } + } +} + +func benchmarkNearestPeers(n int) func(b *testing.B) { + return func(b *testing.B) { + keys := make([]key.KadKey, n) + for i := 0; i < n; i++ { + keys[i] = keyutil.Random(32) + } + rt := New(key0) + for _, kk := range keys { + rt.AddPeer(context.Background(), kadid.NewKadID(kk)) + } + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + rt.NearestPeers(context.Background(), keyutil.Random(32), 20) + } } } From 5b7a773d81b666cbcc03c1ecb9a1e81be7e3e2cd Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:40:00 +0100 Subject: [PATCH 21/32] Add churn benchmark --- routing/triert/table_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index ad79b6f..18fb60f 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -2,6 +2,7 @@ package triert import ( "context" + "math/rand" "testing" "github.com/plprobelab/go-kademlia/key" @@ -350,6 +351,12 @@ func BenchmarkNearestPeers(b *testing.B) { b.Run("100000", benchmarkNearestPeers(100000)) } +func BenchmarkChurn(b *testing.B) { + b.Run("1000", benchmarkChurn(1000)) + b.Run("10000", benchmarkChurn(10000)) + b.Run("100000", benchmarkChurn(100000)) +} + func benchmarkBuildTable(n int) func(b *testing.B) { return func(b *testing.B) { nodes := make([]address.NodeID, n) @@ -432,6 +439,35 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { } } +func benchmarkChurn(n int) func(b *testing.B) { + return func(b *testing.B) { + universe := make([]address.NodeID, n) + for i := 0; i < n; i++ { + universe[i] = kadid.NewKadID(keyutil.Random(32)) + } + rt := New(key0) + // Add a portion of the universe to the routing table + for i := 0; i < len(universe)/4; i++ { + rt.AddPeer(context.Background(), universe[i]) + } + rand.Shuffle(len(universe), func(i, j int) { universe[i], universe[j] = universe[j], universe[i] }) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + node := universe[i%len(universe)] + found, _ := rt.Find(context.Background(), node.Key()) + if found == nil { + // add new peer + rt.AddPeer(context.Background(), universe[i%len(universe)]) + } else { + // remove it + rt.RemoveKey(context.Background(), node.Key()) + } + } + } +} + var _ address.NodeID = (*node)(nil) type node struct { From e70e4ee0e7373f05be9e65bdcb7d8376c5bb69e3 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:21:00 +0100 Subject: [PATCH 22/32] Convert trie README to doc.go --- key/trie/README.md | 5 ----- key/trie/doc.go | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 key/trie/README.md create mode 100644 key/trie/doc.go diff --git a/key/trie/README.md b/key/trie/README.md deleted file mode 100644 index 914a868..0000000 --- a/key/trie/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Trie - -This package contains an implementation of a XOR Trie. - -The trie is to be treated as immutable. Mutator functions such as Add and Remove return copies of the trie. diff --git a/key/trie/doc.go b/key/trie/doc.go new file mode 100644 index 0000000..49df19f --- /dev/null +++ b/key/trie/doc.go @@ -0,0 +1,2 @@ +// Package trie provides an implementation of a XOR Trie. +package trie From b5a1c513fd7fb4d176b9c511d653eccfad78d7dc Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:58:50 +0100 Subject: [PATCH 23/32] Remove concurrent support --- key/key.go | 3 ++ key/trie/trie.go | 19 ++++---- key/trie/trie_test.go | 85 ++++++++++++++++++++++++++++++++++++ routing/triert/doc.go | 2 + routing/triert/table.go | 69 ++++++++--------------------- routing/triert/table_test.go | 4 +- 6 files changed, 121 insertions(+), 61 deletions(-) create mode 100644 routing/triert/doc.go diff --git a/key/key.go b/key/key.go index 347dfe8..01aa27a 100644 --- a/key/key.go +++ b/key/key.go @@ -84,6 +84,9 @@ func (a KadKey) Compare(b KadKey) int { } func (a KadKey) Equal(b KadKey) bool { + if a.Size() != b.Size() { + return false + } return a.Compare(b) == 0 } diff --git a/key/trie/trie.go b/key/trie/trie.go index 6f15ead..85d1985 100644 --- a/key/trie/trie.go +++ b/key/trie/trie.go @@ -114,7 +114,7 @@ func (tr *Trie[T]) firstNonEmptyLeaf() *Trie[T] { return tr.branch[1].firstNonEmptyLeaf() } -// Add attemptes to add a key to the trie, mutating the trie. +// Add attempts to add a key to the trie, mutating the trie. // Returns true if the key was added, false otherwise. func (tr *Trie[T]) Add(kk key.KadKey, data T) (bool, error) { f := tr.firstNonEmptyLeaf() @@ -137,10 +137,14 @@ func (tr *Trie[T]) addAtDepth(depth int, kk key.KadKey, data T) bool { return false } else { p := tr.key + d := tr.data tr.key = nil + var v T + tr.data = v // both branches are nil tr.branch[0], tr.branch[1] = &Trie[T]{}, &Trie[T]{} tr.branch[p.BitAt(depth)].key = p + tr.branch[p.BitAt(depth)].data = d return tr.branch[kk.BitAt(depth)].addAtDepth(depth+1, kk, data) } default: @@ -165,9 +169,6 @@ func addAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey, data T) *Trie[T] { case tr.IsEmptyLeaf(): return &Trie[T]{key: kk, data: data} case tr.IsNonEmptyLeaf(): - if tr.key.Size() != kk.Size() { - return nil - } eq := tr.key.Equal(kk) if eq { return tr @@ -215,6 +216,10 @@ func (tr *Trie[T]) removeAtDepth(depth int, kk key.KadKey) bool { case tr.IsEmptyLeaf(): return false case tr.IsNonEmptyLeaf(): + eq := tr.key.Equal(kk) + if !eq { + return false + } tr.key = nil var v T tr.data = v @@ -223,9 +228,8 @@ func (tr *Trie[T]) removeAtDepth(depth int, kk key.KadKey) bool { if tr.branch[kk.BitAt(depth)].removeAtDepth(depth+1, kk) { tr.shrink() return true - } else { - return false } + return false } } @@ -247,9 +251,6 @@ func removeAtDepth[T any](depth int, tr *Trie[T], kk key.KadKey) *Trie[T] { case tr.IsEmptyLeaf(): return tr case tr.IsNonEmptyLeaf(): - if tr.key.Size() != kk.Size() { - return nil - } eq := tr.key.Equal(kk) if !eq { return tr diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 8e3e20b..6277b35 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -238,6 +238,38 @@ func TestImmutableAddRejectsMismatchedKeyLength(t *testing.T) { } } +func TestAddWithData(t *testing.T) { + tr := New[int]() + for i, kk := range sampleKeySet.Keys { + added, err := tr.Add(kk, i) + require.NoError(t, err) + require.True(t, added) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + for i, kk := range sampleKeySet.Keys { + found, v := Find(tr, kk) + require.True(t, found) + require.Equal(t, i, v) + } +} + +func TestImmutableAddWithData(t *testing.T) { + tr := New[int]() + var err error + for i, kk := range sampleKeySet.Keys { + tr, err = Add(tr, kk, i) + require.NoError(t, err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + for i, kk := range sampleKeySet.Keys { + found, v := Find(tr, kk) + require.True(t, found) + require.Equal(t, i, v) + } +} + func TestRemove(t *testing.T) { tr, err := trieFromKeys[any](sampleKeySet.Keys) if err != nil { @@ -325,6 +357,45 @@ func TestImmutableRemoveRejectsMismatchedKeyLength(t *testing.T) { } } +func TestRemoveUnknown(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + unknown := newKeyNotInSet(sampleKeySet.Keys[0].Size(), sampleKeySet) + + removed, err := tr.Remove(unknown) + require.NoError(t, err) + require.False(t, removed) + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + if d := CheckInvariant(tr); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + +func TestImmutableRemoveUnknown(t *testing.T) { + tr, err := trieFromKeys[any](sampleKeySet.Keys) + if err != nil { + t.Fatalf("unexpected error during from keys: %v", err) + } + require.Equal(t, len(sampleKeySet.Keys), tr.Size()) + + unknown := newKeyNotInSet(sampleKeySet.Keys[0].Size(), sampleKeySet) + + trNext, err := Remove(tr, unknown) + require.NoError(t, err) + + // trie has not been changed + require.Same(t, tr, trNext) + + if d := CheckInvariant(trNext); d != nil { + t.Fatalf("reordered trie invariant discrepancy: %v", d) + } +} + func TestEqual(t *testing.T) { a, err := trieFromKeys[any](sampleKeySet.Keys) if err != nil { @@ -681,6 +752,20 @@ func newKeySetOfLength(n int, l int) *keySet { } } +func newKeyNotInSet(l int, ks *keySet) key.KadKey { + seen := make(map[string]bool) + for i := range ks.Keys { + seen[ks.Keys[i].String()] = true + } + + kk := keyutil.Random(l) + for seen[kk.String()] { + kk = keyutil.Random(l) + } + + return kk +} + type InvariantDiscrepancy struct { Reason string PathToDiscrepancy string diff --git a/routing/triert/doc.go b/routing/triert/doc.go new file mode 100644 index 0000000..ca4ac87 --- /dev/null +++ b/routing/triert/doc.go @@ -0,0 +1,2 @@ +// Package triert provides a routing table implemented using a XOR trie. +package triert diff --git a/routing/triert/table.go b/routing/triert/table.go index 733e413..cb8e24c 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -2,25 +2,18 @@ package triert import ( "context" - "sync" - "sync/atomic" "github.com/plprobelab/go-kademlia/key" "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" ) -// TrieRT is a routing table backed by a Xor Trie which offers good scalablity and performance -// for large networks. All exported methods are safe for concurrent use. +// TrieRT is a routing table backed by a XOR Trie which offers good scalablity and performance +// for large networks. type TrieRT struct { self key.KadKey - // keymu is held during trie mutations to serialize changes - keymu sync.Mutex - - // keys holds a pointer to an immutable trie - // any store to keys must be performed while holding keymu, loads may be performed without the lock - keys atomic.Value + keys *nodeTrie } type nodeTrie = trie.Trie[address.NodeID] @@ -28,8 +21,8 @@ type nodeTrie = trie.Trie[address.NodeID] func New(self key.KadKey) *TrieRT { rt := &TrieRT{ self: self, + keys: &nodeTrie{}, } - rt.keys.Store(&nodeTrie{}) return rt } @@ -44,21 +37,7 @@ func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error return false, trie.ErrMismatchedKeyLength } - rt.keymu.Lock() - defer rt.keymu.Unlock() - // load the old trie, derive a mutated variant and store it in place of the original - keys := rt.keys.Load().(*nodeTrie) - keysNext, err := trie.Add(keys, kk, node) - if err != nil { - return false, err - } - - // if trie is unchanged then we didn't add the key - if keysNext == keys { - return false, nil - } - rt.keys.Store(keysNext) - return true, nil + return rt.keys.Add(kk, node) } // RemoveKey tries to remove a peer identified by its Kademlia key from the @@ -67,21 +46,7 @@ func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { if kk.Size() != rt.self.Size() { return false, trie.ErrMismatchedKeyLength } - rt.keymu.Lock() - defer rt.keymu.Unlock() - // load the old trie, derive a mutated variant and store it in place of the original - keys := rt.keys.Load().(*nodeTrie) - keysNext, err := trie.Remove(keys, kk) - if err != nil { - return false, err - } - // if trie is unchanged then we didn't remove the key - if keysNext == keys { - return false, nil - } - - rt.keys.Store(keysNext) - return true, nil + return rt.keys.Remove(kk) } // NearestPeers returns the n closest peers to a given key @@ -90,8 +55,7 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add return nil, trie.ErrMismatchedKeyLength } - keys := rt.keys.Load().(*nodeTrie) - closestEntries := closestAtDepth(kk, keys, 0, n) + closestEntries := closestAtDepth(kk, rt.keys, 0, n) if len(closestEntries) == 0 { return []address.NodeID{}, nil } @@ -121,6 +85,10 @@ func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { return nil } + if depth > kk.BitLen() { + return nil + } + // Find the closest direction. dir := kk.BitAt(depth) // Add peers from the closest direction first @@ -137,10 +105,7 @@ func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, erro return nil, trie.ErrMismatchedKeyLength } - keys := rt.keys.Load().(*nodeTrie) - - found, node := trie.Find(keys, kk) - + found, node := trie.Find(rt.keys, kk) if found { return node, nil } @@ -150,14 +115,12 @@ func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, erro // Size returns the number of peers contained in the table. func (rt *TrieRT) Size() int { - keys := rt.keys.Load().(*nodeTrie) - return keys.Size() + return rt.keys.Size() } // CplSize returns the number of peers in the table whose longest common prefix with the table's key is of length cpl. func (rt *TrieRT) CplSize(cpl int) int { - keys := rt.keys.Load().(*nodeTrie) - n, err := countCpl(keys, rt.self, cpl, 0) + n, err := countCpl(rt.keys, rt.self, cpl, 0) if err != nil { return 0 } @@ -177,6 +140,10 @@ func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { return 0, nil } + if depth > kk.BitLen() { + return 0, nil + } + if depth == cpl { // return the number of entries that do not share the next bit with kk return t.Branch(1 - kk.BitAt(depth)).Size(), nil diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 18fb60f..94d001c 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -103,7 +103,9 @@ func TestAddPeer(t *testing.T) { func TestRemovePeer(t *testing.T) { rt := New(key0) - rt.AddPeer(context.Background(), node1) + success, err := rt.AddPeer(context.Background(), node1) + require.NoError(t, err) + require.True(t, success) t.Run("unknown peer", func(t *testing.T) { success, err := rt.RemoveKey(context.Background(), key2) From e92cc8007664bc6fb7c181cf977f861ec7762654 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:12:08 +0100 Subject: [PATCH 24/32] Fix build on older versions of Go --- internal/testutil/bench.go | 11 +++++++++++ internal/testutil/bench_pre120.go | 9 +++++++++ key/trie/trie_test.go | 13 +++++++------ routing/triert/table_test.go | 3 ++- 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 internal/testutil/bench.go create mode 100644 internal/testutil/bench_pre120.go diff --git a/internal/testutil/bench.go b/internal/testutil/bench.go new file mode 100644 index 0000000..842bbfa --- /dev/null +++ b/internal/testutil/bench.go @@ -0,0 +1,11 @@ +//go:build go1.20 + +package testutil + +import "testing" + +// ReportTimePerItemMetric adds a custom metric to a benchmark that reports the number of nanoseconds taken per item. +func ReportTimePerItemMetric(b *testing.B, n int, name string) { + // b.Elapsed was added in Go 1.20 + b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(n), "ns/"+name) +} diff --git a/internal/testutil/bench_pre120.go b/internal/testutil/bench_pre120.go new file mode 100644 index 0000000..b0a47d2 --- /dev/null +++ b/internal/testutil/bench_pre120.go @@ -0,0 +1,9 @@ +//go:build !go1.20 + +package testutil + +import "testing" + +func ReportTimePerKeyMetric(b *testing.B, n int) { + // no-op +} diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 6277b35..3f85842 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -4,6 +4,7 @@ import ( "math/rand" "testing" + "github.com/plprobelab/go-kademlia/internal/testutil" "github.com/plprobelab/go-kademlia/key" "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/stretchr/testify/require" @@ -537,7 +538,7 @@ func benchmarkBuildTrieMutable(n int) func(b *testing.B) { tr.Add(kk, nil) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(n), "ns/key") + testutil.ReportTimePerItemMetric(b, n, "key") } } @@ -555,7 +556,7 @@ func benchmarkBuildTrieImmutable(n int) func(b *testing.B) { tr, _ = Add(tr, kk, nil) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(n), "ns/key") + testutil.ReportTimePerItemMetric(b, n, "key") } } @@ -587,7 +588,7 @@ func benchmarkAddMutable(n int) func(b *testing.B) { trclone.Add(kk, nil) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(additions)), "ns/key") + testutil.ReportTimePerItemMetric(b, len(additions), "key") } } @@ -614,7 +615,7 @@ func benchmarkAddImmutable(n int) func(b *testing.B) { tr, _ = Add(tr, kk, nil) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(additions)), "ns/key") + testutil.ReportTimePerItemMetric(b, len(additions), "key") } } @@ -646,7 +647,7 @@ func benchmarkRemoveMutable(n int) func(b *testing.B) { trclone.Remove(kk) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(removals)), "ns/key") + testutil.ReportTimePerItemMetric(b, len(removals), "key") } } @@ -673,7 +674,7 @@ func benchmarkRemoveImmutable(n int) func(b *testing.B) { tr, _ = Remove(tr, kk) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(removals)), "ns/key") + testutil.ReportTimePerItemMetric(b, len(removals), "key") } } diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 94d001c..4aeea87 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -5,6 +5,7 @@ import ( "math/rand" "testing" + "github.com/plprobelab/go-kademlia/internal/testutil" "github.com/plprobelab/go-kademlia/key" "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/plprobelab/go-kademlia/key/trie" @@ -373,7 +374,7 @@ func benchmarkBuildTable(n int) func(b *testing.B) { rt.AddPeer(context.Background(), node) } } - b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(len(nodes)), "ns/node") + testutil.ReportTimePerItemMetric(b, len(nodes), "node") } } From ce88d3be387771debeac6eb3c9dbd0489c704d56 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:16:05 +0100 Subject: [PATCH 25/32] Fix build on older versions of Go again --- internal/testutil/bench_pre120.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/testutil/bench_pre120.go b/internal/testutil/bench_pre120.go index b0a47d2..37548e7 100644 --- a/internal/testutil/bench_pre120.go +++ b/internal/testutil/bench_pre120.go @@ -4,6 +4,7 @@ package testutil import "testing" -func ReportTimePerKeyMetric(b *testing.B, n int) { +// ReportTimePerItemMetric is a no-op on versions of Go before 1.20 +func ReportTimePerItemMetric(b *testing.B, n int) { // no-op } From e262f292a80a1967c7fbef2e34804ad71b5c2c39 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:18:38 +0100 Subject: [PATCH 26/32] Fix method signature of ReportTimePerItemMetric on pre 1.20 versions of Go --- internal/testutil/bench_pre120.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/testutil/bench_pre120.go b/internal/testutil/bench_pre120.go index 37548e7..b869c41 100644 --- a/internal/testutil/bench_pre120.go +++ b/internal/testutil/bench_pre120.go @@ -5,6 +5,6 @@ package testutil import "testing" // ReportTimePerItemMetric is a no-op on versions of Go before 1.20 -func ReportTimePerItemMetric(b *testing.B, n int) { +func ReportTimePerItemMetric(b *testing.B, n int, name string) { // no-op } From 608229b691f211b233927694e15a60d825bfefe0 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:30:20 +0100 Subject: [PATCH 27/32] Add key filters --- routing/triert/config.go | 15 +++++ routing/triert/filter.go | 13 +++++ routing/triert/filter_test.go | 55 +++++++++++++++++++ routing/triert/table.go | 47 ++++++++++++---- routing/triert/table_test.go | 100 +++++++++++++++++++++++++++------- 5 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 routing/triert/config.go create mode 100644 routing/triert/filter.go create mode 100644 routing/triert/filter_test.go diff --git a/routing/triert/config.go b/routing/triert/config.go new file mode 100644 index 0000000..5c02128 --- /dev/null +++ b/routing/triert/config.go @@ -0,0 +1,15 @@ +package triert + +// Config holds configuration options for a TrieRT. +type Config struct { + // KeyFilter defines the filter that is applied before a key is added to the table. + // If nil, no filter is applied. + KeyFilter KeyFilterFunc +} + +// DefaultConfig returns a default configuration for a TrieRT. +func DefaultConfig() *Config { + return &Config{ + KeyFilter: nil, + } +} diff --git a/routing/triert/filter.go b/routing/triert/filter.go new file mode 100644 index 0000000..bcd7310 --- /dev/null +++ b/routing/triert/filter.go @@ -0,0 +1,13 @@ +package triert + +import "github.com/plprobelab/go-kademlia/key" + +// KeyFilterFunc is a function that is applied before a key is added to the table. +// Return false to prevent the key from being added. +type KeyFilterFunc func(rt *TrieRT, kk key.KadKey) bool + +// BucketLimit20 is a filter function that limits the occupancy of buckets in the table to 20 keys. +func BucketLimit20(rt *TrieRT, kk key.KadKey) bool { + cpl := rt.Cpl(kk) + return rt.CplSize(cpl) < 20 +} diff --git a/routing/triert/filter_test.go b/routing/triert/filter_test.go new file mode 100644 index 0000000..1f02bd8 --- /dev/null +++ b/routing/triert/filter_test.go @@ -0,0 +1,55 @@ +package triert + +import ( + "context" + "fmt" + "testing" + + "github.com/plprobelab/go-kademlia/key/keyutil" + "github.com/plprobelab/go-kademlia/network/address" + "github.com/stretchr/testify/require" +) + +func TestBucketLimit20(t *testing.T) { + ctx := context.Background() + + cfg := DefaultConfig() + cfg.KeyFilter = BucketLimit20 + rt, err := New(key0, cfg) + require.NoError(t, err) + + nodes := make([]address.NodeID, 21) + for i := range nodes { + kk := keyutil.RandomWithPrefix("000100", 32) + nodes[i] = NewNode(fmt.Sprintf("QmPeer%d", i), kk) + } + + // Add 20 peers with cpl 3 + for i := 0; i < 20; i++ { + success, err := rt.AddPeer(ctx, nodes[i]) + require.NoError(t, err) + require.True(t, success) + } + + // cannot add 21st + success, err := rt.AddPeer(ctx, nodes[20]) + require.NoError(t, err) + require.False(t, success) + + // add peer with different cpl + kk := keyutil.RandomWithPrefix("0000100", 32) + node22 := NewNode("QmPeer22", kk) + success, err = rt.AddPeer(ctx, node22) + require.NoError(t, err) + require.True(t, success) + + // make space for another cpl 3 key + success, err = rt.RemoveKey(ctx, nodes[0].Key()) + require.NoError(t, err) + require.True(t, success) + + // now can add cpl 3 key + success, err = rt.AddPeer(ctx, nodes[20]) + require.NoError(t, err) + require.True(t, success) +} diff --git a/routing/triert/table.go b/routing/triert/table.go index cb8e24c..eae263e 100644 --- a/routing/triert/table.go +++ b/routing/triert/table.go @@ -2,6 +2,7 @@ package triert import ( "context" + "fmt" "github.com/plprobelab/go-kademlia/key" "github.com/plprobelab/go-kademlia/key/trie" @@ -11,37 +12,58 @@ import ( // TrieRT is a routing table backed by a XOR Trie which offers good scalablity and performance // for large networks. type TrieRT struct { - self key.KadKey + self key.KadKey + keyFilter KeyFilterFunc keys *nodeTrie } type nodeTrie = trie.Trie[address.NodeID] -func New(self key.KadKey) *TrieRT { +// New creates a new TrieRT using the supplied key as the local node's Kademlia key. +// If cfg is nil, the default config is used. +func New(self key.KadKey, cfg *Config) (*TrieRT, error) { rt := &TrieRT{ self: self, keys: &nodeTrie{}, } - return rt + if err := rt.apply(cfg); err != nil { + return nil, fmt.Errorf("apply config: %w", err) + } + return rt, nil +} + +func (rt *TrieRT) apply(cfg *Config) error { + if cfg == nil { + cfg = DefaultConfig() + } + + rt.keyFilter = cfg.KeyFilter + + return nil } +// Self returns the local node's Kademlia key. func (rt *TrieRT) Self() key.KadKey { return rt.self } -// AddPeer tries to add a peer to the routing table +// AddPeer tries to add a peer to the routing table. func (rt *TrieRT) AddPeer(ctx context.Context, node address.NodeID) (bool, error) { kk := node.Key() if kk.Size() != rt.self.Size() { return false, trie.ErrMismatchedKeyLength } + if rt.keyFilter != nil && !rt.keyFilter(rt, kk) { + return false, nil + } + return rt.keys.Add(kk, node) } // RemoveKey tries to remove a peer identified by its Kademlia key from the -// routing table +// routing table. It returns true if the key was found to be present in the table and was removed. func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { if kk.Size() != rt.self.Size() { return false, trie.ErrMismatchedKeyLength @@ -49,7 +71,7 @@ func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { return rt.keys.Remove(kk) } -// NearestPeers returns the n closest peers to a given key +// NearestPeers returns the n closest peers to a given key. func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]address.NodeID, error) { if kk.Size() != rt.self.Size() { return nil, trie.ErrMismatchedKeyLength @@ -62,15 +84,15 @@ func (rt *TrieRT) NearestPeers(ctx context.Context, kk key.KadKey, n int) ([]add nodes := make([]address.NodeID, 0, len(closestEntries)) for _, c := range closestEntries { - nodes = append(nodes, c.Data) + nodes = append(nodes, c.data) } return nodes, nil } type entry struct { - Key key.KadKey - Data address.NodeID + key key.KadKey + data address.NodeID } func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { @@ -78,7 +100,7 @@ func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { if t.HasKey() { // We've found a leaf return []entry{ - {Key: t.Key(), Data: t.Data()}, + {key: t.Key(), data: t.Data()}, } } // We've found an empty node? @@ -118,6 +140,11 @@ func (rt *TrieRT) Size() int { return rt.keys.Size() } +// Cpl returns the longest common prefix length the supplied key shares with the table's key. +func (rt *TrieRT) Cpl(kk key.KadKey) int { + return rt.self.CommonPrefixLength(kk) +} + // CplSize returns the number of peers in the table whose longest common prefix with the table's key is of length cpl. func (rt *TrieRT) CplSize(cpl int) int { n, err := countCpl(rt.keys, rt.self, cpl, 0) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 4aeea87..161f8b0 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -40,11 +40,17 @@ var ( node9 = NewNode("QmPeer9", key9) node10 = NewNode("QmPeer10", key10) node11 = NewNode("QmPeer11", key11) + + testNodes = []address.NodeID{ + node1, node2, node3, node4, node5, node6, + node7, node8, node9, node10, node11, + } ) func TestAddPeer(t *testing.T) { t.Run("one", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -52,7 +58,8 @@ func TestAddPeer(t *testing.T) { }) t.Run("ignore duplicate", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -65,7 +72,8 @@ func TestAddPeer(t *testing.T) { }) t.Run("many", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -103,7 +111,8 @@ func TestAddPeer(t *testing.T) { } func TestRemovePeer(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -123,7 +132,8 @@ func TestRemovePeer(t *testing.T) { func TestFindPeer(t *testing.T) { t.Run("known peer", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -135,14 +145,16 @@ func TestFindPeer(t *testing.T) { }) t.Run("unknown peer", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) got, err := rt.Find(context.Background(), key2) require.NoError(t, err) require.Nil(t, got) }) t.Run("removed peer", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(context.Background(), node1) require.NoError(t, err) require.True(t, success) @@ -165,7 +177,8 @@ func TestFindPeer(t *testing.T) { func TestNearestPeers(t *testing.T) { ctx := context.Background() - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) rt.AddPeer(ctx, node1) rt.AddPeer(ctx, node2) rt.AddPeer(ctx, node3) @@ -196,7 +209,8 @@ func TestInvalidKeys(t *testing.T) { incompatKey := key.KadKey(make([]byte, 4)) // key is shorter (4 bytes only) incompatNode := NewNode("inv", incompatKey) - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) t.Run("add peer", func(t *testing.T) { success, err := rt.AddPeer(ctx, incompatNode) @@ -225,7 +239,8 @@ func TestInvalidKeys(t *testing.T) { func TestCplSize(t *testing.T) { t.Run("empty", func(t *testing.T) { - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) require.Equal(t, 0, rt.Size()) require.Equal(t, 0, rt.CplSize(1)) require.Equal(t, 0, rt.CplSize(2)) @@ -235,7 +250,8 @@ func TestCplSize(t *testing.T) { t.Run("cpl 1", func(t *testing.T) { ctx := context.Background() - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) @@ -252,7 +268,8 @@ func TestCplSize(t *testing.T) { t.Run("cpl 2", func(t *testing.T) { ctx := context.Background() - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyutil.RandomWithPrefix("001", 32))) require.NoError(t, err) @@ -270,7 +287,8 @@ func TestCplSize(t *testing.T) { t.Run("cpl 3", func(t *testing.T) { ctx := context.Background() - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) @@ -294,7 +312,8 @@ func TestCplSize(t *testing.T) { t.Run("cpl mixed", func(t *testing.T) { ctx := context.Background() - rt := New(key0) + rt, err := New(key0, nil) + require.NoError(t, err) success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) require.NoError(t, err) @@ -330,6 +349,34 @@ func TestCplSize(t *testing.T) { }) } +func TestKeyFilter(t *testing.T) { + ctx := context.Background() + cfg := DefaultConfig() + cfg.KeyFilter = func(rt *TrieRT, kk key.KadKey) bool { + return !kk.Equal(key2) // don't allow key2 to be added + } + rt, err := New(key0, cfg) + + // can't add key2 + success, err := rt.AddPeer(ctx, node2) + require.NoError(t, err) + require.False(t, success) + + got, err := rt.Find(ctx, key2) + require.NoError(t, err) + require.Nil(t, got) + + // can add other key + success, err = rt.AddPeer(ctx, node1) + require.NoError(t, err) + require.True(t, success) + + want := node1 + got, err = rt.Find(ctx, key1) + require.NoError(t, err) + require.Equal(t, want, got) +} + func BenchmarkBuildTable(b *testing.B) { b.Run("1000", benchmarkBuildTable(1000)) b.Run("10000", benchmarkBuildTable(10000)) @@ -369,7 +416,10 @@ func benchmarkBuildTable(n int) func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - rt := New(key0) + rt, err := New(key0, nil) + if err != nil { + b.Fatalf("unexpected error creating table: %v", err) + } for _, node := range nodes { rt.AddPeer(context.Background(), node) } @@ -384,7 +434,10 @@ func benchmarkFindPositive(n int) func(b *testing.B) { for i := 0; i < n; i++ { keys[i] = keyutil.Random(32) } - rt := New(key0) + rt, err := New(key0, nil) + if err != nil { + b.Fatalf("unexpected error creating table: %v", err) + } for _, kk := range keys { rt.AddPeer(context.Background(), kadid.NewKadID(kk)) } @@ -402,7 +455,10 @@ func benchmarkFindNegative(n int) func(b *testing.B) { for i := 0; i < n; i++ { keys[i] = keyutil.Random(32) } - rt := New(key0) + rt, err := New(key0, nil) + if err != nil { + b.Fatalf("unexpected error creating table: %v", err) + } for _, kk := range keys { rt.AddPeer(context.Background(), kadid.NewKadID(kk)) } @@ -430,7 +486,10 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { for i := 0; i < n; i++ { keys[i] = keyutil.Random(32) } - rt := New(key0) + rt, err := New(key0, nil) + if err != nil { + b.Fatalf("unexpected error creating table: %v", err) + } for _, kk := range keys { rt.AddPeer(context.Background(), kadid.NewKadID(kk)) } @@ -448,7 +507,10 @@ func benchmarkChurn(n int) func(b *testing.B) { for i := 0; i < n; i++ { universe[i] = kadid.NewKadID(keyutil.Random(32)) } - rt := New(key0) + rt, err := New(key0, nil) + if err != nil { + b.Fatalf("unexpected error creating table: %v", err) + } // Add a portion of the universe to the routing table for i := 0; i < len(universe)/4; i++ { rt.AddPeer(context.Background(), universe[i]) From 08b8669983439c7fa56a1581c6d7a366cdfffeee Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:53:11 +0100 Subject: [PATCH 28/32] Fix lint issues --- routing/triert/table_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 161f8b0..24d580b 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -40,11 +40,6 @@ var ( node9 = NewNode("QmPeer9", key9) node10 = NewNode("QmPeer10", key10) node11 = NewNode("QmPeer11", key11) - - testNodes = []address.NodeID{ - node1, node2, node3, node4, node5, node6, - node7, node8, node9, node10, node11, - } ) func TestAddPeer(t *testing.T) { @@ -356,6 +351,7 @@ func TestKeyFilter(t *testing.T) { return !kk.Equal(key2) // don't allow key2 to be added } rt, err := New(key0, cfg) + require.NoError(t, err) // can't add key2 success, err := rt.AddPeer(ctx, node2) From 29a8ef150f93bd318f2a8c1238b81b914977a4e0 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:22:46 +0100 Subject: [PATCH 29/32] Panic if BitAt index out of range --- key/key.go | 3 +++ key/key_test.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/key/key.go b/key/key.go index 01aa27a..5c14e71 100644 --- a/key/key.go +++ b/key/key.go @@ -97,6 +97,9 @@ func (k KadKey) BitLen() int { // BitAt returns the value of the i'th bit of the key from most significant to least. It is equivalent to (key>>(bitlen-i-1))&1. func (k KadKey) BitAt(i int) int { + if i < 0 || i > k.BitLen()-1 { + panic("BitAt: index out of range") + } if k[i/8]&(byte(1)<<(7-i%8)) == 0 { return 0 } else { diff --git a/key/key_test.go b/key/key_test.go index e5c6832..fe3a423 100644 --- a/key/key_test.go +++ b/key/key_test.go @@ -124,4 +124,7 @@ func TestBitAt(t *testing.T) { require.Equal(t, 1, kk.BitAt(7)) require.Equal(t, 1, kk.BitAt(8)) require.Equal(t, 0, kk.BitAt(15)) + + require.Panics(t, func() { kk.BitAt(-1) }) + require.Panics(t, func() { kk.BitAt(16) }) } From 5e3f1c9b332946593624c32820461dd44adb534f Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:25:33 +0100 Subject: [PATCH 30/32] Move merge keyutil package into testutil --- .../keyutil.go => internal/testutil/rand.go | 2 +- key/trie/trie_test.go | 39 +++++------ routing/triert/filter_test.go | 6 +- routing/triert/table_test.go | 69 +++++++++---------- 4 files changed, 57 insertions(+), 59 deletions(-) rename key/keyutil/keyutil.go => internal/testutil/rand.go (98%) diff --git a/key/keyutil/keyutil.go b/internal/testutil/rand.go similarity index 98% rename from key/keyutil/keyutil.go rename to internal/testutil/rand.go index 4fbeee5..a744536 100644 --- a/key/keyutil/keyutil.go +++ b/internal/testutil/rand.go @@ -1,4 +1,4 @@ -package keyutil +package testutil import ( "encoding/binary" diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 3f85842..02c4aa7 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -6,7 +6,6 @@ import ( "github.com/plprobelab/go-kademlia/internal/testutil" "github.com/plprobelab/go-kademlia/key" - "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/stretchr/testify/require" ) @@ -213,7 +212,7 @@ func TestAddRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - added, err := tr.Add(keyutil.Random(5), nil) + added, err := tr.Add(testutil.Random(5), nil) require.ErrorIs(t, err, ErrMismatchedKeyLength) require.False(t, added) @@ -228,7 +227,7 @@ func TestImmutableAddRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - trNext, err := Add(tr, keyutil.Random(5), nil) + trNext, err := Add(tr, testutil.Random(5), nil) require.ErrorIs(t, err, ErrMismatchedKeyLength) // trie has not been changed @@ -332,7 +331,7 @@ func TestRemoveRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - removed, err := tr.Remove(keyutil.Random(5)) + removed, err := tr.Remove(testutil.Random(5)) require.ErrorIs(t, err, ErrMismatchedKeyLength) require.False(t, removed) @@ -347,7 +346,7 @@ func TestImmutableRemoveRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - trNext, err := Remove(tr, keyutil.Random(5)) + trNext, err := Remove(tr, testutil.Random(5)) require.ErrorIs(t, err, ErrMismatchedKeyLength) // trie has not been changed @@ -456,7 +455,7 @@ func TestFindMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - found, _ := Find(tr, keyutil.Random(5)) + found, _ := Find(tr, testutil.Random(5)) require.False(t, found) } @@ -528,7 +527,7 @@ func benchmarkBuildTrieMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } b.ResetTimer() b.ReportAllocs() @@ -546,7 +545,7 @@ func benchmarkBuildTrieImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } b.ResetTimer() b.ReportAllocs() @@ -564,7 +563,7 @@ func benchmarkAddMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } tr := New[any]() for _, kk := range keys { @@ -576,7 +575,7 @@ func benchmarkAddMutable(n int) func(b *testing.B) { // see https://github.com/golang/go/issues/27217 additions := make([]key.KadKey, n/4) for i := range additions { - additions[i] = keyutil.Random(32) + additions[i] = testutil.Random(32) } b.ResetTimer() b.ReportAllocs() @@ -596,7 +595,7 @@ func benchmarkAddImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } trBase := New[any]() for _, kk := range keys { @@ -605,7 +604,7 @@ func benchmarkAddImmutable(n int) func(b *testing.B) { additions := make([]key.KadKey, n/4) for i := range additions { - additions[i] = keyutil.Random(32) + additions[i] = testutil.Random(32) } b.ResetTimer() b.ReportAllocs() @@ -623,7 +622,7 @@ func benchmarkRemoveMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } tr := New[any]() for _, kk := range keys { @@ -655,7 +654,7 @@ func benchmarkRemoveImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } trBase := New[any]() for _, kk := range keys { @@ -682,7 +681,7 @@ func benchmarkFindPositive(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } tr := New[any]() for _, kk := range keys { @@ -700,7 +699,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } tr := New[any]() for _, kk := range keys { @@ -708,7 +707,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { } unknown := make([]key.KadKey, n) for i := 0; i < n; i++ { - kk := keyutil.Random(32) + kk := testutil.Random(32) if found, _ := Find(tr, kk); found { continue } @@ -741,7 +740,7 @@ func newKeySetOfLength(n int, l int) *keySet { set := make([]key.KadKey, 0, n) seen := make(map[string]bool) for len(set) < n { - kk := keyutil.Random(l) + kk := testutil.Random(l) if seen[kk.String()] { continue } @@ -759,9 +758,9 @@ func newKeyNotInSet(l int, ks *keySet) key.KadKey { seen[ks.Keys[i].String()] = true } - kk := keyutil.Random(l) + kk := testutil.Random(l) for seen[kk.String()] { - kk = keyutil.Random(l) + kk = testutil.Random(l) } return kk diff --git a/routing/triert/filter_test.go b/routing/triert/filter_test.go index 1f02bd8..1d68f04 100644 --- a/routing/triert/filter_test.go +++ b/routing/triert/filter_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/plprobelab/go-kademlia/key/keyutil" + "github.com/plprobelab/go-kademlia/internal/testutil" "github.com/plprobelab/go-kademlia/network/address" "github.com/stretchr/testify/require" ) @@ -20,7 +20,7 @@ func TestBucketLimit20(t *testing.T) { nodes := make([]address.NodeID, 21) for i := range nodes { - kk := keyutil.RandomWithPrefix("000100", 32) + kk := testutil.RandomWithPrefix("000100", 32) nodes[i] = NewNode(fmt.Sprintf("QmPeer%d", i), kk) } @@ -37,7 +37,7 @@ func TestBucketLimit20(t *testing.T) { require.False(t, success) // add peer with different cpl - kk := keyutil.RandomWithPrefix("0000100", 32) + kk := testutil.RandomWithPrefix("0000100", 32) node22 := NewNode("QmPeer22", kk) success, err = rt.AddPeer(ctx, node22) require.NoError(t, err) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 24d580b..680a145 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -7,7 +7,6 @@ import ( "github.com/plprobelab/go-kademlia/internal/testutil" "github.com/plprobelab/go-kademlia/key" - "github.com/plprobelab/go-kademlia/key/keyutil" "github.com/plprobelab/go-kademlia/key/trie" "github.com/plprobelab/go-kademlia/network/address" "github.com/plprobelab/go-kademlia/network/address/kadid" @@ -17,17 +16,17 @@ import ( var ( key0 = key.KadKey(make([]byte, 32)) // 000000...000 - key1 = keyutil.RandomWithPrefix("010000", 32) - key2 = keyutil.RandomWithPrefix("100000", 32) - key3 = keyutil.RandomWithPrefix("110000", 32) - key4 = keyutil.RandomWithPrefix("111000", 32) - key5 = keyutil.RandomWithPrefix("011000", 32) - key6 = keyutil.RandomWithPrefix("011100", 32) - key7 = keyutil.RandomWithPrefix("000110", 32) - key8 = keyutil.RandomWithPrefix("000101", 32) - key9 = keyutil.RandomWithPrefix("000100", 32) - key10 = keyutil.RandomWithPrefix("001000", 32) - key11 = keyutil.RandomWithPrefix("001100", 32) + key1 = testutil.RandomWithPrefix("010000", 32) + key2 = testutil.RandomWithPrefix("100000", 32) + key3 = testutil.RandomWithPrefix("110000", 32) + key4 = testutil.RandomWithPrefix("111000", 32) + key5 = testutil.RandomWithPrefix("011000", 32) + key6 = testutil.RandomWithPrefix("011100", 32) + key7 = testutil.RandomWithPrefix("000110", 32) + key8 = testutil.RandomWithPrefix("000101", 32) + key9 = testutil.RandomWithPrefix("000100", 32) + key10 = testutil.RandomWithPrefix("001000", 32) + key11 = testutil.RandomWithPrefix("001100", 32) node1 = NewNode("QmPeer1", key1) node2 = NewNode("QmPeer2", key2) @@ -248,10 +247,10 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyutil.RandomWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) require.Equal(t, 2, rt.Size()) @@ -266,10 +265,10 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl2a", keyutil.RandomWithPrefix("001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) @@ -285,16 +284,16 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl3a", keyutil.RandomWithPrefix("0001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) @@ -310,30 +309,30 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", keyutil.RandomWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", keyutil.RandomWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2a", keyutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", keyutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3a", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", keyutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 32))) require.NoError(t, err) require.True(t, success) @@ -407,7 +406,7 @@ func benchmarkBuildTable(n int) func(b *testing.B) { return func(b *testing.B) { nodes := make([]address.NodeID, n) for i := 0; i < n; i++ { - nodes[i] = kadid.NewKadID(keyutil.Random(32)) + nodes[i] = kadid.NewKadID(testutil.Random(32)) } b.ResetTimer() b.ReportAllocs() @@ -428,7 +427,7 @@ func benchmarkFindPositive(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } rt, err := New(key0, nil) if err != nil { @@ -449,7 +448,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } rt, err := New(key0, nil) if err != nil { @@ -461,7 +460,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { unknown := make([]key.KadKey, n) for i := 0; i < n; i++ { - kk := keyutil.Random(32) + kk := testutil.Random(32) if found, _ := rt.Find(context.Background(), kk); found != nil { continue } @@ -480,7 +479,7 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = keyutil.Random(32) + keys[i] = testutil.Random(32) } rt, err := New(key0, nil) if err != nil { @@ -492,7 +491,7 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - rt.NearestPeers(context.Background(), keyutil.Random(32), 20) + rt.NearestPeers(context.Background(), testutil.Random(32), 20) } } } @@ -501,7 +500,7 @@ func benchmarkChurn(n int) func(b *testing.B) { return func(b *testing.B) { universe := make([]address.NodeID, n) for i := 0; i < n; i++ { - universe[i] = kadid.NewKadID(keyutil.Random(32)) + universe[i] = kadid.NewKadID(testutil.Random(32)) } rt, err := New(key0, nil) if err != nil { From 0b284ff7c4ee1794031b17c27f303f1930206217 Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:29:24 +0100 Subject: [PATCH 31/32] Check input length of RandomWithPrefix --- internal/testutil/rand.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/testutil/rand.go b/internal/testutil/rand.go index a744536..f1fdd7d 100644 --- a/internal/testutil/rand.go +++ b/internal/testutil/rand.go @@ -18,6 +18,7 @@ func Random(l int) key.KadKey { } // RandomWithPrefix returns a KadKey of length l having a prefix equal to the bit pattern held in s. +// A prefix of up to 64 bits is supported. func RandomWithPrefix(s string, l int) key.KadKey { kk := Random(l) if s == "" { @@ -27,6 +28,8 @@ func RandomWithPrefix(s string, l int) key.KadKey { bits := len(s) if bits > 64 { panic("RandomWithPrefix: prefix too long") + } else if bits > l*8 { + panic("RandomWithPrefix: prefix longer than key length") } n, err := strconv.ParseInt(s, 2, 64) if err != nil { From 23f01c15eedeb9523be00478a5c7026cfec1adae Mon Sep 17 00:00:00 2001 From: Ian Davis <18375+iand@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:45:14 +0100 Subject: [PATCH 32/32] Random key generation uses bitlength instead of byte length --- internal/testutil/rand.go | 36 ++++++++++--------- key/trie/trie_test.go | 52 +++++++++++++-------------- routing/triert/filter_test.go | 4 +-- routing/triert/table_test.go | 68 +++++++++++++++++------------------ 4 files changed, 81 insertions(+), 79 deletions(-) diff --git a/internal/testutil/rand.go b/internal/testutil/rand.go index f1fdd7d..21dda68 100644 --- a/internal/testutil/rand.go +++ b/internal/testutil/rand.go @@ -10,45 +10,47 @@ import ( var rng = rand.New(rand.NewSource(299792458)) -// Random returns a KadKey of length l populated with random data. -func Random(l int) key.KadKey { - buf := make([]byte, l) +// Random returns a KadKey with the specificed number of bits populated with random data. +func Random(bits int) key.KadKey { + buf := make([]byte, (bits+7)/8) rng.Read(buf) return buf } -// RandomWithPrefix returns a KadKey of length l having a prefix equal to the bit pattern held in s. +// RandomWithPrefix returns a KadKey with the specificed number of bits having a prefix equal to the bit pattern held in s. // A prefix of up to 64 bits is supported. -func RandomWithPrefix(s string, l int) key.KadKey { - kk := Random(l) +func RandomWithPrefix(s string, bits int) key.KadKey { + kk := Random(bits) if s == "" { return kk } - bits := len(s) - if bits > 64 { + prefixbits := len(s) + if prefixbits > 64 { panic("RandomWithPrefix: prefix too long") - } else if bits > l*8 { + } else if prefixbits > bits { panic("RandomWithPrefix: prefix longer than key length") } n, err := strconv.ParseInt(s, 2, 64) if err != nil { panic("RandomWithPrefix: " + err.Error()) } - prefix := uint64(n) << (64 - bits) + prefix := uint64(n) << (64 - prefixbits) - size := l - if size < 8 { - size = 8 + // sizes are in bytes + keySize := (bits + 7) / 8 + bufSize := keySize + if bufSize < 8 { + bufSize = 8 } - buf := make([]byte, size) + buf := make([]byte, bufSize) rng.Read(buf) lead := binary.BigEndian.Uint64(buf) - lead <<= bits - lead >>= bits + lead <<= prefixbits + lead >>= prefixbits lead |= prefix binary.BigEndian.PutUint64(buf, lead) - return key.KadKey(buf[:l]) + return key.KadKey(buf[:keySize]) } diff --git a/key/trie/trie_test.go b/key/trie/trie_test.go index 02c4aa7..a575cb7 100644 --- a/key/trie/trie_test.go +++ b/key/trie/trie_test.go @@ -212,7 +212,7 @@ func TestAddRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - added, err := tr.Add(testutil.Random(5), nil) + added, err := tr.Add(testutil.Random(40), nil) require.ErrorIs(t, err, ErrMismatchedKeyLength) require.False(t, added) @@ -227,7 +227,7 @@ func TestImmutableAddRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - trNext, err := Add(tr, testutil.Random(5), nil) + trNext, err := Add(tr, testutil.Random(40), nil) require.ErrorIs(t, err, ErrMismatchedKeyLength) // trie has not been changed @@ -331,7 +331,7 @@ func TestRemoveRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - removed, err := tr.Remove(testutil.Random(5)) + removed, err := tr.Remove(testutil.Random(40)) require.ErrorIs(t, err, ErrMismatchedKeyLength) require.False(t, removed) @@ -346,7 +346,7 @@ func TestImmutableRemoveRejectsMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - trNext, err := Remove(tr, testutil.Random(5)) + trNext, err := Remove(tr, testutil.Random(40)) require.ErrorIs(t, err, ErrMismatchedKeyLength) // trie has not been changed @@ -364,7 +364,7 @@ func TestRemoveUnknown(t *testing.T) { } require.Equal(t, len(sampleKeySet.Keys), tr.Size()) - unknown := newKeyNotInSet(sampleKeySet.Keys[0].Size(), sampleKeySet) + unknown := newKeyNotInSet(sampleKeySet.Keys[0].BitLen(), sampleKeySet) removed, err := tr.Remove(unknown) require.NoError(t, err) @@ -383,7 +383,7 @@ func TestImmutableRemoveUnknown(t *testing.T) { } require.Equal(t, len(sampleKeySet.Keys), tr.Size()) - unknown := newKeyNotInSet(sampleKeySet.Keys[0].Size(), sampleKeySet) + unknown := newKeyNotInSet(sampleKeySet.Keys[0].BitLen(), sampleKeySet) trNext, err := Remove(tr, unknown) require.NoError(t, err) @@ -407,7 +407,7 @@ func TestEqual(t *testing.T) { } require.True(t, Equal(a, b)) - sampleKeySet2 := newKeySetOfLength(12, 8) + sampleKeySet2 := newKeySetOfLength(12, 64) c, err := trieFromKeys[any](sampleKeySet2.Keys) if err != nil { t.Fatalf("unexpected error during from keys: %v", err) @@ -455,7 +455,7 @@ func TestFindMismatchedKeyLength(t *testing.T) { t.Fatalf("unexpected error during from keys: %v", err) } - found, _ := Find(tr, testutil.Random(5)) + found, _ := Find(tr, testutil.Random(40)) require.False(t, found) } @@ -527,7 +527,7 @@ func benchmarkBuildTrieMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } b.ResetTimer() b.ReportAllocs() @@ -545,7 +545,7 @@ func benchmarkBuildTrieImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } b.ResetTimer() b.ReportAllocs() @@ -563,7 +563,7 @@ func benchmarkAddMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } tr := New[any]() for _, kk := range keys { @@ -575,7 +575,7 @@ func benchmarkAddMutable(n int) func(b *testing.B) { // see https://github.com/golang/go/issues/27217 additions := make([]key.KadKey, n/4) for i := range additions { - additions[i] = testutil.Random(32) + additions[i] = testutil.Random(256) } b.ResetTimer() b.ReportAllocs() @@ -595,7 +595,7 @@ func benchmarkAddImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } trBase := New[any]() for _, kk := range keys { @@ -604,7 +604,7 @@ func benchmarkAddImmutable(n int) func(b *testing.B) { additions := make([]key.KadKey, n/4) for i := range additions { - additions[i] = testutil.Random(32) + additions[i] = testutil.Random(256) } b.ResetTimer() b.ReportAllocs() @@ -622,7 +622,7 @@ func benchmarkRemoveMutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } tr := New[any]() for _, kk := range keys { @@ -654,7 +654,7 @@ func benchmarkRemoveImmutable(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } trBase := New[any]() for _, kk := range keys { @@ -681,7 +681,7 @@ func benchmarkFindPositive(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } tr := New[any]() for _, kk := range keys { @@ -699,7 +699,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } tr := New[any]() for _, kk := range keys { @@ -707,7 +707,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { } unknown := make([]key.KadKey, n) for i := 0; i < n; i++ { - kk := testutil.Random(32) + kk := testutil.Random(256) if found, _ := Find(tr, kk); found { continue } @@ -726,21 +726,21 @@ type keySet struct { Keys []key.KadKey } -var sampleKeySet = newKeySetOfLength(12, 8) +var sampleKeySet = newKeySetOfLength(12, 64) func newKeySetList(n int) []*keySet { s := make([]*keySet, n) for i := range s { - s[i] = newKeySetOfLength(31, 4) + s[i] = newKeySetOfLength(31, 32) } return s } -func newKeySetOfLength(n int, l int) *keySet { +func newKeySetOfLength(n int, bits int) *keySet { set := make([]key.KadKey, 0, n) seen := make(map[string]bool) for len(set) < n { - kk := testutil.Random(l) + kk := testutil.Random(bits) if seen[kk.String()] { continue } @@ -752,15 +752,15 @@ func newKeySetOfLength(n int, l int) *keySet { } } -func newKeyNotInSet(l int, ks *keySet) key.KadKey { +func newKeyNotInSet(bits int, ks *keySet) key.KadKey { seen := make(map[string]bool) for i := range ks.Keys { seen[ks.Keys[i].String()] = true } - kk := testutil.Random(l) + kk := testutil.Random(bits) for seen[kk.String()] { - kk = testutil.Random(l) + kk = testutil.Random(bits) } return kk diff --git a/routing/triert/filter_test.go b/routing/triert/filter_test.go index 1d68f04..47b0d96 100644 --- a/routing/triert/filter_test.go +++ b/routing/triert/filter_test.go @@ -20,7 +20,7 @@ func TestBucketLimit20(t *testing.T) { nodes := make([]address.NodeID, 21) for i := range nodes { - kk := testutil.RandomWithPrefix("000100", 32) + kk := testutil.RandomWithPrefix("000100", 256) nodes[i] = NewNode(fmt.Sprintf("QmPeer%d", i), kk) } @@ -37,7 +37,7 @@ func TestBucketLimit20(t *testing.T) { require.False(t, success) // add peer with different cpl - kk := testutil.RandomWithPrefix("0000100", 32) + kk := testutil.RandomWithPrefix("0000100", 256) node22 := NewNode("QmPeer22", kk) success, err = rt.AddPeer(ctx, node22) require.NoError(t, err) diff --git a/routing/triert/table_test.go b/routing/triert/table_test.go index 680a145..06e95b6 100644 --- a/routing/triert/table_test.go +++ b/routing/triert/table_test.go @@ -16,17 +16,17 @@ import ( var ( key0 = key.KadKey(make([]byte, 32)) // 000000...000 - key1 = testutil.RandomWithPrefix("010000", 32) - key2 = testutil.RandomWithPrefix("100000", 32) - key3 = testutil.RandomWithPrefix("110000", 32) - key4 = testutil.RandomWithPrefix("111000", 32) - key5 = testutil.RandomWithPrefix("011000", 32) - key6 = testutil.RandomWithPrefix("011100", 32) - key7 = testutil.RandomWithPrefix("000110", 32) - key8 = testutil.RandomWithPrefix("000101", 32) - key9 = testutil.RandomWithPrefix("000100", 32) - key10 = testutil.RandomWithPrefix("001000", 32) - key11 = testutil.RandomWithPrefix("001100", 32) + key1 = testutil.RandomWithPrefix("010000", 256) + key2 = testutil.RandomWithPrefix("100000", 256) + key3 = testutil.RandomWithPrefix("110000", 256) + key4 = testutil.RandomWithPrefix("111000", 256) + key5 = testutil.RandomWithPrefix("011000", 256) + key6 = testutil.RandomWithPrefix("011100", 256) + key7 = testutil.RandomWithPrefix("000110", 256) + key8 = testutil.RandomWithPrefix("000101", 256) + key9 = testutil.RandomWithPrefix("000100", 256) + key10 = testutil.RandomWithPrefix("001000", 256) + key11 = testutil.RandomWithPrefix("001100", 256) node1 = NewNode("QmPeer1", key1) node2 = NewNode("QmPeer2", key2) @@ -247,10 +247,10 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 256))) require.NoError(t, err) require.True(t, success) require.Equal(t, 2, rt.Size()) @@ -265,10 +265,10 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 256))) require.NoError(t, err) require.True(t, success) @@ -284,16 +284,16 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) @@ -309,30 +309,30 @@ func TestCplSize(t *testing.T) { rt, err := New(key0, nil) require.NoError(t, err) - success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 32))) + success, err := rt.AddPeer(ctx, NewNode("cpl1a", testutil.RandomWithPrefix("01", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl1b", testutil.RandomWithPrefix("01", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2a", testutil.RandomWithPrefix("001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl2b", testutil.RandomWithPrefix("001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3a", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3b", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3c", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) - success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 32))) + success, err = rt.AddPeer(ctx, NewNode("cpl3d", testutil.RandomWithPrefix("0001", 256))) require.NoError(t, err) require.True(t, success) @@ -406,7 +406,7 @@ func benchmarkBuildTable(n int) func(b *testing.B) { return func(b *testing.B) { nodes := make([]address.NodeID, n) for i := 0; i < n; i++ { - nodes[i] = kadid.NewKadID(testutil.Random(32)) + nodes[i] = kadid.NewKadID(testutil.Random(256)) } b.ResetTimer() b.ReportAllocs() @@ -427,7 +427,7 @@ func benchmarkFindPositive(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } rt, err := New(key0, nil) if err != nil { @@ -448,7 +448,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } rt, err := New(key0, nil) if err != nil { @@ -460,7 +460,7 @@ func benchmarkFindNegative(n int) func(b *testing.B) { unknown := make([]key.KadKey, n) for i := 0; i < n; i++ { - kk := testutil.Random(32) + kk := testutil.Random(256) if found, _ := rt.Find(context.Background(), kk); found != nil { continue } @@ -479,7 +479,7 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { return func(b *testing.B) { keys := make([]key.KadKey, n) for i := 0; i < n; i++ { - keys[i] = testutil.Random(32) + keys[i] = testutil.Random(256) } rt, err := New(key0, nil) if err != nil { @@ -491,7 +491,7 @@ func benchmarkNearestPeers(n int) func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - rt.NearestPeers(context.Background(), testutil.Random(32), 20) + rt.NearestPeers(context.Background(), testutil.Random(256), 20) } } } @@ -500,7 +500,7 @@ func benchmarkChurn(n int) func(b *testing.B) { return func(b *testing.B) { universe := make([]address.NodeID, n) for i := 0; i < n; i++ { - universe[i] = kadid.NewKadID(testutil.Random(32)) + universe[i] = kadid.NewKadID(testutil.Random(256)) } rt, err := New(key0, nil) if err != nil {